U-Boot
Threads by month
- ----- 2025 -----
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2000 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
January 2012
- 182 participants
- 465 discussions
Hi Stefan,
I address this question to you because one of your commits is connected to this
problem, but other hints from other readers are also welcome ;-) .
We have a kirkwood based board with a micron NAND flash. We have one ubi device
created on the NAND flash and inside the device we have one ubi volume were we
store our linux kernel. At startup we attach to the ubi device, to be able to
readout the kernel image. On our old u-boot branch which based on v2009.08 we
hadn't any problems. Now after upgrading to the newest u-boot version we saw in
some rarely cases our u-boot get stuck when we try to attach:
=> ubi part ubi0
Creating 1 MTD partitions on "nand0":
0x000000000000-0x000008000000 : "mtd=0"
UBI: attaching mtd1 to ubi0
UBI: physical eraseblock size: 131072 bytes (128 KiB)
UBI: logical eraseblock size: 129024 bytes
UBI: smallest flash I/O unit: 2048
UBI: sub-page size: 512
UBI: VID header offset: 512 (aligned 512)
UBI: data offset: 2048
UBI: fixable bit-flip detected at PEB 71
And after this u-boot gets stuck until the end of days and we have to force a
reboot, but the u-boot gets stuck again.
If I revert your commit:
commit 1b1f9a9d00447d9eab32ae5633f60a106196b75f
Author: Stefan Roese <sr(a)denx.de>
Date: Mon May 17 10:00:51 2010 +0200
UBI: Ensure that "background thread" operations are really executed
the u-boot don't get stuck:
=> ubi part ubi0
Creating 1 MTD partitions on "nand0":
0x000000000000-0x000008000000 : "mtd=0"
UBI: attaching mtd1 to ubi0
UBI: physical eraseblock size: 131072 bytes (128 KiB)
UBI: logical eraseblock size: 129024 bytes
UBI: smallest flash I/O unit: 2048
UBI: sub-page size: 512
UBI: VID header offset: 512 (aligned 512)
UBI: data offset: 2048
UBI: fixable bit-flip detected at PEB 71
UBI: attached mtd1 to ubi0
UBI: MTD device name: "mtd=0"
UBI: MTD device size: 128 MiB
UBI: number of good PEBs: 1024
UBI: number of bad PEBs: 0
UBI: max. allowed volumes: 128
UBI: wear-leveling threshold: 4096
UBI: number of internal volumes: 1
UBI: number of user volumes: 9
UBI: available PEBs: 623
UBI: total number of reserved PEBs: 401
UBI: number of PEBs reserved for bad PEB handling: 10
UBI: max/mean erase counter: 8193/3082
=>
This is the reason why our old u-boot works, because the background thread seems
to be not or not completely executed...
If I boot a recent linux kernel the kernel also reports an "fixable bit-flip
detected at PEB 71" but linux is able to really fix this bit flip and is able to
work as expceted, even u-boot is afterwards bootable because the bitflip is
corrected and gone.
Now I could revert your commit in my local branch and then it seems to work, but
I think this is not a good solution because I expect that the real error is
somewhere in the UBI layer in u-boot and already fixed in current linux. AFAIK
the ubi layer was initially copied from linux, but it seems that the bugfixes
are not backported in the last years. Any thoughts or ideas?
Best regards
Holger
3
10
From: Uma Shankar <uma.shankar(a)samsung.com>
Signed-off-by: Uma Shankar <uma.shankar(a)samsung.com>
Signed-off-by: Manjunatha C Achar <a.manjunatha(a)samsung.com>
Signed-off-by: Iqbal Shareef <iqbal.ams(a)samsung.com>
Signed-off-by: Hakgoo Lee <goodguy.lee(a)samsung.com>
---
Makefile | 2 +-
common/Makefile | 1 +
common/cmd_ext2.c | 1 +
common/cmd_ext4.c | 253 ++++++++++++++++++++++
fs/Makefile | 1 +
fs/ext2/dev.c | 1 +
fs/ext2/ext2fs.c | 340 +++---------------------------
fs/ext4/Makefile | 51 +++++
fs/ext4/ext4_common.c | 573 +++++++++++++++++++++++++++++++++++++++++++++++++
fs/ext4/ext4_common.h | 44 ++++
fs/ext4/ext4fs.c | 215 ++++++++++++++++++
include/ext2fs.h | 16 +-
include/ext4fs.h | 116 ++++++++++
include/ext_common.h | 199 +++++++++++++++++
14 files changed, 1489 insertions(+), 324 deletions(-)
create mode 100644 common/cmd_ext4.c
create mode 100644 fs/ext4/Makefile
create mode 100644 fs/ext4/ext4_common.c
create mode 100644 fs/ext4/ext4_common.h
create mode 100644 fs/ext4/ext4fs.c
create mode 100644 include/ext4fs.h
create mode 100644 include/ext_common.h
diff --git a/Makefile b/Makefile
index 5de7915..20cb941 100644
--- a/Makefile
+++ b/Makefile
@@ -235,7 +235,7 @@ LIBS += dts/libdts.o
endif
LIBS += arch/$(ARCH)/lib/lib$(ARCH).o
LIBS += fs/cramfs/libcramfs.o fs/fat/libfat.o fs/fdos/libfdos.o fs/jffs2/libjffs2.o \
- fs/reiserfs/libreiserfs.o fs/ext2/libext2fs.o fs/yaffs2/libyaffs2.o \
+ fs/reiserfs/libreiserfs.o fs/ext2/libext2fs.o fs/ext4/libext4fs.o fs/yaffs2/libyaffs2.o \
fs/ubifs/libubifs.o
LIBS += net/libnet.o
LIBS += disk/libdisk.o
diff --git a/common/Makefile b/common/Makefile
index 2d9ae8c..d99cc31 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -87,6 +87,7 @@ COBJS-$(CONFIG_CMD_EEPROM) += cmd_eeprom.o
COBJS-$(CONFIG_CMD_ELF) += cmd_elf.o
COBJS-$(CONFIG_SYS_HUSH_PARSER) += cmd_exit.o
COBJS-$(CONFIG_CMD_EXT2) += cmd_ext2.o
+COBJS-$(CONFIG_CMD_EXT4) += cmd_ext4.o
COBJS-$(CONFIG_CMD_FAT) += cmd_fat.o
COBJS-$(CONFIG_CMD_FDC)$(CONFIG_CMD_FDOS) += cmd_fdc.o
COBJS-$(CONFIG_OF_LIBFDT) += cmd_fdt.o fdt_support.o
diff --git a/common/cmd_ext2.c b/common/cmd_ext2.c
index 35fb361..3ccc47e 100644
--- a/common/cmd_ext2.c
+++ b/common/cmd_ext2.c
@@ -40,6 +40,7 @@
#include <linux/ctype.h>
#include <asm/byteorder.h>
#include <ext2fs.h>
+#include <ext_common.h>
#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE)
#include <usb.h>
#endif
diff --git a/common/cmd_ext4.c b/common/cmd_ext4.c
new file mode 100644
index 0000000..7c2d541
--- /dev/null
+++ b/common/cmd_ext4.c
@@ -0,0 +1,253 @@
+/*
+ * (C) Copyright 2011 Samsung Electronics
+ * EXT4 filesystem implementation in Uboot by
+ * Uma Shankar <uma.shankar(a)samsung.com>
+ * Manjunatha C Achar <a.manjunatha(a)samsung.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+/*
+ * Ext4fs support
+ * made from existing cmd_ext2.c file of Uboot
+ */
+#include <common.h>
+#include <part.h>
+#include <config.h>
+#include <command.h>
+#include <image.h>
+#include <linux/ctype.h>
+#include <asm/byteorder.h>
+#include <ext_common.h>
+#include <ext4fs.h>
+#include <linux/stat.h>
+#include <malloc.h>
+
+#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE)
+#include <usb.h>
+#endif
+
+#if !defined(CONFIG_DOS_PARTITION) && !defined(CONFIG_EFI_PARTITION)
+#error DOS or EFI partition support must be selected
+#endif
+
+uint64_t total_sector;
+uint64_t part_offset;
+
+#define DOS_PART_MAGIC_OFFSET 0x1fe
+#define DOS_FS_TYPE_OFFSET 0x36
+#define DOS_FS32_TYPE_OFFSET 0x52
+
+int do_ext4_load(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+ char *filename = NULL;
+ char *ep;
+ int dev;
+ unsigned long part = 1;
+ ulong addr = 0, part_length;
+ int filelen;
+ disk_partition_t info;
+ struct ext_filesystem *fs;
+ char buf[12];
+ unsigned long count;
+ const char *addr_str;
+
+ switch (argc) {
+ case 3:
+ addr_str = getenv("loadaddr");
+ if (addr_str != NULL)
+ strict_strtoul(addr_str, 16, &addr);
+ else
+ addr = CONFIG_SYS_LOAD_ADDR;
+
+ filename = getenv("bootfile");
+ count = 0;
+ break;
+ case 4:
+ strict_strtoul(argv[3], 16, &addr);
+ filename = getenv("bootfile");
+ count = 0;
+ break;
+ case 5:
+ strict_strtoul(argv[3], 16, &addr);
+ filename = argv[4];
+ count = 0;
+ break;
+ case 6:
+ strict_strtoul(argv[3], 16, &addr);
+ filename = argv[4];
+ strict_strtoul(argv[5], 16, &count);
+ break;
+
+ default:
+ return cmd_usage(cmdtp);
+ }
+
+ if (!filename) {
+ puts("** No boot file defined **\n");
+ return 1;
+ }
+
+ dev = (int)simple_strtoul(argv[2], &ep, 16);
+ ext4_dev_desc = get_dev(argv[1], dev);
+ if (ext4_dev_desc == NULL) {
+ printf("** Block device %s %d not supported\n", argv[1], dev);
+ return 1;
+ }
+ if (init_fs(ext4_dev_desc))
+ return 1;
+
+ fs = get_fs();
+ if (*ep) {
+ if (*ep != ':') {
+ puts("** Invalid boot device, use `dev[:part]' **\n");
+ return 1;
+ }
+ (int)strict_strtoul(++ep, 16, &part);
+ }
+
+ if (part != 0) {
+ if (get_partition_info(fs->dev_desc, part, &info)) {
+ printf("** Bad partition %lu **\n", part);
+ return 1;
+ }
+
+ if (strncmp((char *)info.type, BOOT_PART_TYPE,
+ sizeof(info.type)) != 0) {
+ printf("** Invalid partition type \"%.32s\""
+ " (expect \"" BOOT_PART_TYPE "\")\n", info.type);
+ return 1;
+ }
+ printf("Loading file \"%s\" "
+ "from %s device %d:%lu (%.32s)\n",
+ filename, argv[1], dev, part, info.name);
+ } else {
+ printf("Loading file \"%s\" from %s device %d\n",
+ filename, argv[1], dev);
+ }
+
+ part_length = ext2fs_set_blk_dev(fs->dev_desc, part);
+ if (part_length == 0) {
+ printf("**Bad partition - %s %d:%lu **\n", argv[1], dev, part);
+ ext4fs_close();
+ return 1;
+ }
+
+ if (!ext4fs_mount(part_length)) {
+ printf("** Bad ext2 partition or disk - %s %d:%lu **\n",
+ argv[1], dev, part);
+ ext4fs_close();
+ return 1;
+ }
+
+ filelen = ext4fs_open(filename);
+ if (filelen < 0) {
+ printf("** File not found %s\n", filename);
+ ext4fs_close();
+ return 1;
+ }
+ if ((count < filelen) && (count != 0))
+ filelen = count;
+
+ if (ext4fs_read((char *)addr, filelen) != filelen) {
+ printf("** Unable to read \"%s\" from %s %d:%lu **\n",
+ filename, argv[1], dev, part);
+ ext4fs_close();
+ return 1;
+ }
+
+ ext4fs_close();
+ deinit_fs(fs->dev_desc);
+ /* Loading ok, update default load address */
+ load_addr = addr;
+
+ printf("%d bytes read\n", filelen);
+ sprintf(buf, "%X", filelen);
+ setenv("filesize", buf);
+
+ return 0;
+}
+
+int do_ext4_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+ char *filename = "/";
+ int dev = 0;
+ unsigned long part = 1;
+ char *ep;
+ struct ext_filesystem *fs;
+ int part_length;
+
+ if (argc < 3)
+ return cmd_usage(cmdtp);
+
+ dev = (int)simple_strtoul(argv[2], &ep, 16);
+ ext4_dev_desc = get_dev(argv[1], dev);
+
+ if (ext4_dev_desc == NULL) {
+ printf("\n** Block device %s %d not supported\n", argv[1], dev);
+ return 1;
+ }
+
+ if (init_fs(ext4_dev_desc))
+ return 1;
+
+ fs = get_fs();
+ if (*ep) {
+ if (*ep != ':') {
+ puts("\n** Invalid boot device, use `dev[:part]' **\n");
+ return 1;
+ }
+ (int)strict_strtoul(++ep, 16, &part);
+ }
+
+ if (argc == 4)
+ filename = argv[3];
+
+ part_length = ext2fs_set_blk_dev(fs->dev_desc, part);
+ if (part_length == 0) {
+ printf("** Bad partition - %s %d:%lu **\n", argv[1], dev, part);
+ ext4fs_close();
+ return 1;
+ }
+
+ if (!ext4fs_mount(part_length)) {
+ printf("** Bad ext2 partition or disk - %s %d:%lu **\n",
+ argv[1], dev, part);
+ ext4fs_close();
+ return 1;
+ }
+ if (ext4fs_ls(filename)) {
+ printf("** Error ext2fs_ls() **\n");
+ ext4fs_close();
+ return 1;
+ };
+
+ ext4fs_close();
+ deinit_fs(fs->dev_desc);
+ return 0;
+}
+
+U_BOOT_CMD(ext4ls, 4, 1, do_ext4_ls,
+ "list files in a directory (default /)",
+ "<interface> <dev[:part]> [directory]\n"
+ " - list files from 'dev' on 'interface' in a 'directory'");
+
+U_BOOT_CMD(ext4load, 6, 0, do_ext4_load,
+ "load binary file from a Ext2 filesystem",
+ "<interface> <dev[:part]> [addr] [filename] [bytes]\n"
+ " - load binary file 'filename' from 'dev' on 'interface'\n"
+ " to address 'addr' from ext2 filesystem");
diff --git a/fs/Makefile b/fs/Makefile
index 22aad12..27330d4 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -24,6 +24,7 @@
subdirs-$(CONFIG_CMD_CRAMFS) := cramfs
subdirs-$(CONFIG_CMD_EXT2) += ext2
+subdirs-$(CONFIG_CMD_EXT4) += ext4
subdirs-$(CONFIG_CMD_FAT) += fat
subdirs-$(CONFIG_CMD_FDOS) += fdos
subdirs-$(CONFIG_CMD_JFFS2) += jffs2
diff --git a/fs/ext2/dev.c b/fs/ext2/dev.c
index 874e211..315ff53 100644
--- a/fs/ext2/dev.c
+++ b/fs/ext2/dev.c
@@ -27,6 +27,7 @@
#include <common.h>
#include <config.h>
#include <ext2fs.h>
+#include <ext_common.h>
static block_dev_desc_t *ext2fs_block_dev_desc;
static disk_partition_t part_info;
diff --git a/fs/ext2/ext2fs.c b/fs/ext2/ext2fs.c
index e119e13..df336b9 100644
--- a/fs/ext2/ext2fs.c
+++ b/fs/ext2/ext2fs.c
@@ -25,152 +25,12 @@
#include <common.h>
#include <ext2fs.h>
+#include <ext_common.h>
#include <malloc.h>
#include <asm/byteorder.h>
-extern int ext2fs_devread (int sector, int byte_offset, int byte_len,
- char *buf);
-
-/* Magic value used to identify an ext2 filesystem. */
-#define EXT2_MAGIC 0xEF53
-/* Amount of indirect blocks in an inode. */
-#define INDIRECT_BLOCKS 12
-/* Maximum lenght of a pathname. */
-#define EXT2_PATH_MAX 4096
-/* Maximum nesting of symlinks, used to prevent a loop. */
-#define EXT2_MAX_SYMLINKCNT 8
-
-/* Filetype used in directory entry. */
-#define FILETYPE_UNKNOWN 0
-#define FILETYPE_REG 1
-#define FILETYPE_DIRECTORY 2
-#define FILETYPE_SYMLINK 7
-
-/* Filetype information as used in inodes. */
-#define FILETYPE_INO_MASK 0170000
-#define FILETYPE_INO_REG 0100000
-#define FILETYPE_INO_DIRECTORY 0040000
-#define FILETYPE_INO_SYMLINK 0120000
-
-/* Bits used as offset in sector */
-#define DISK_SECTOR_BITS 9
-
-/* Log2 size of ext2 block in 512 blocks. */
-#define LOG2_EXT2_BLOCK_SIZE(data) (__le32_to_cpu (data->sblock.log2_block_size) + 1)
-
-/* Log2 size of ext2 block in bytes. */
-#define LOG2_BLOCK_SIZE(data) (__le32_to_cpu (data->sblock.log2_block_size) + 10)
-
-/* The size of an ext2 block in bytes. */
-#define EXT2_BLOCK_SIZE(data) (1 << LOG2_BLOCK_SIZE(data))
-
-/* The ext2 superblock. */
-struct ext2_sblock {
- uint32_t total_inodes;
- uint32_t total_blocks;
- uint32_t reserved_blocks;
- uint32_t free_blocks;
- uint32_t free_inodes;
- uint32_t first_data_block;
- uint32_t log2_block_size;
- uint32_t log2_fragment_size;
- uint32_t blocks_per_group;
- uint32_t fragments_per_group;
- uint32_t inodes_per_group;
- uint32_t mtime;
- uint32_t utime;
- uint16_t mnt_count;
- uint16_t max_mnt_count;
- uint16_t magic;
- uint16_t fs_state;
- uint16_t error_handling;
- uint16_t minor_revision_level;
- uint32_t lastcheck;
- uint32_t checkinterval;
- uint32_t creator_os;
- uint32_t revision_level;
- uint16_t uid_reserved;
- uint16_t gid_reserved;
- uint32_t first_inode;
- uint16_t inode_size;
- uint16_t block_group_number;
- uint32_t feature_compatibility;
- uint32_t feature_incompat;
- uint32_t feature_ro_compat;
- uint32_t unique_id[4];
- char volume_name[16];
- char last_mounted_on[64];
- uint32_t compression_info;
-};
-
-/* The ext2 blockgroup. */
-struct ext2_block_group {
- uint32_t block_id;
- uint32_t inode_id;
- uint32_t inode_table_id;
- uint16_t free_blocks;
- uint16_t free_inodes;
- uint16_t used_dir_cnt;
- uint32_t reserved[3];
-};
-
-/* The ext2 inode. */
-struct ext2_inode {
- uint16_t mode;
- uint16_t uid;
- uint32_t size;
- uint32_t atime;
- uint32_t ctime;
- uint32_t mtime;
- uint32_t dtime;
- uint16_t gid;
- uint16_t nlinks;
- uint32_t blockcnt; /* Blocks of 512 bytes!! */
- uint32_t flags;
- uint32_t osd1;
- union {
- struct datablocks {
- uint32_t dir_blocks[INDIRECT_BLOCKS];
- uint32_t indir_block;
- uint32_t double_indir_block;
- uint32_t tripple_indir_block;
- } blocks;
- char symlink[60];
- } b;
- uint32_t version;
- uint32_t acl;
- uint32_t dir_acl;
- uint32_t fragment_addr;
- uint32_t osd2[3];
-};
-
-/* The header of an ext2 directory entry. */
-struct ext2_dirent {
- uint32_t inode;
- uint16_t direntlen;
- uint8_t namelen;
- uint8_t filetype;
-};
-
-struct ext2fs_node {
- struct ext2_data *data;
- struct ext2_inode inode;
- int ino;
- int inode_read;
-};
-
-/* Information about a "mounted" ext2 filesystem. */
-struct ext2_data {
- struct ext2_sblock sblock;
- struct ext2_inode *inode;
- struct ext2fs_node diropen;
-};
-
-
-typedef struct ext2fs_node *ext2fs_node_t;
-
-struct ext2_data *ext2fs_root = NULL;
-ext2fs_node_t ext2fs_file = NULL;
+struct ext2_data *ext2fs_root;
+struct ext2fs_node *ext2fs_file;
int symlinknest = 0;
uint32_t *indir1_block = NULL;
int indir1_size = 0;
@@ -178,8 +38,7 @@ int indir1_blkno = -1;
uint32_t *indir2_block = NULL;
int indir2_size = 0;
int indir2_blkno = -1;
-static unsigned int inode_size;
-
+unsigned int inode_size;
static int ext2fs_blockgroup
(struct ext2_data *data, int group, struct ext2_block_group *blkgrp) {
@@ -198,10 +57,8 @@ static int ext2fs_blockgroup
#endif
return (ext2fs_devread (blkno << LOG2_EXT2_BLOCK_SIZE(data),
blkoff, sizeof(struct ext2_block_group), (char *)blkgrp));
-
}
-
static int ext2fs_read_inode
(struct ext2_data *data, int ino, struct ext2_inode *inode) {
struct ext2_block_group blkgrp;
@@ -242,155 +99,16 @@ static int ext2fs_read_inode
return (1);
}
-
-void ext2fs_free_node (ext2fs_node_t node, ext2fs_node_t currroot) {
+void ext2fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot)
+{
if ((node != &ext2fs_root->diropen) && (node != currroot)) {
free (node);
}
}
-
-static int ext2fs_read_block (ext2fs_node_t node, int fileblock) {
- struct ext2_data *data = node->data;
- struct ext2_inode *inode = &node->inode;
- int blknr;
- int blksz = EXT2_BLOCK_SIZE (data);
- int log2_blksz = LOG2_EXT2_BLOCK_SIZE (data);
- int status;
-
- /* Direct blocks. */
- if (fileblock < INDIRECT_BLOCKS) {
- blknr = __le32_to_cpu (inode->b.blocks.dir_blocks[fileblock]);
- }
- /* Indirect. */
- else if (fileblock < (INDIRECT_BLOCKS + (blksz / 4))) {
- if (indir1_block == NULL) {
- indir1_block = (uint32_t *) malloc (blksz);
- if (indir1_block == NULL) {
- printf ("** ext2fs read block (indir 1) malloc failed. **\n");
- return (-1);
- }
- indir1_size = blksz;
- indir1_blkno = -1;
- }
- if (blksz != indir1_size) {
- free (indir1_block);
- indir1_block = NULL;
- indir1_size = 0;
- indir1_blkno = -1;
- indir1_block = (uint32_t *) malloc (blksz);
- if (indir1_block == NULL) {
- printf ("** ext2fs read block (indir 1) malloc failed. **\n");
- return (-1);
- }
- indir1_size = blksz;
- }
- if ((__le32_to_cpu (inode->b.blocks.indir_block) <<
- log2_blksz) != indir1_blkno) {
- status = ext2fs_devread (__le32_to_cpu(inode->b.blocks.indir_block) << log2_blksz,
- 0, blksz,
- (char *) indir1_block);
- if (status == 0) {
- printf ("** ext2fs read block (indir 1) failed. **\n");
- return (0);
- }
- indir1_blkno =
- __le32_to_cpu (inode->b.blocks.
- indir_block) << log2_blksz;
- }
- blknr = __le32_to_cpu (indir1_block
- [fileblock - INDIRECT_BLOCKS]);
- }
- /* Double indirect. */
- else if (fileblock <
- (INDIRECT_BLOCKS + (blksz / 4 * (blksz / 4 + 1)))) {
- unsigned int perblock = blksz / 4;
- unsigned int rblock = fileblock - (INDIRECT_BLOCKS
- + blksz / 4);
-
- if (indir1_block == NULL) {
- indir1_block = (uint32_t *) malloc (blksz);
- if (indir1_block == NULL) {
- printf ("** ext2fs read block (indir 2 1) malloc failed. **\n");
- return (-1);
- }
- indir1_size = blksz;
- indir1_blkno = -1;
- }
- if (blksz != indir1_size) {
- free (indir1_block);
- indir1_block = NULL;
- indir1_size = 0;
- indir1_blkno = -1;
- indir1_block = (uint32_t *) malloc (blksz);
- if (indir1_block == NULL) {
- printf ("** ext2fs read block (indir 2 1) malloc failed. **\n");
- return (-1);
- }
- indir1_size = blksz;
- }
- if ((__le32_to_cpu (inode->b.blocks.double_indir_block) <<
- log2_blksz) != indir1_blkno) {
- status = ext2fs_devread (__le32_to_cpu(inode->b.blocks.double_indir_block) << log2_blksz,
- 0, blksz,
- (char *) indir1_block);
- if (status == 0) {
- printf ("** ext2fs read block (indir 2 1) failed. **\n");
- return (-1);
- }
- indir1_blkno =
- __le32_to_cpu (inode->b.blocks.double_indir_block) << log2_blksz;
- }
-
- if (indir2_block == NULL) {
- indir2_block = (uint32_t *) malloc (blksz);
- if (indir2_block == NULL) {
- printf ("** ext2fs read block (indir 2 2) malloc failed. **\n");
- return (-1);
- }
- indir2_size = blksz;
- indir2_blkno = -1;
- }
- if (blksz != indir2_size) {
- free (indir2_block);
- indir2_block = NULL;
- indir2_size = 0;
- indir2_blkno = -1;
- indir2_block = (uint32_t *) malloc (blksz);
- if (indir2_block == NULL) {
- printf ("** ext2fs read block (indir 2 2) malloc failed. **\n");
- return (-1);
- }
- indir2_size = blksz;
- }
- if ((__le32_to_cpu (indir1_block[rblock / perblock]) <<
- log2_blksz) != indir2_blkno) {
- status = ext2fs_devread (__le32_to_cpu(indir1_block[rblock / perblock]) << log2_blksz,
- 0, blksz,
- (char *) indir2_block);
- if (status == 0) {
- printf ("** ext2fs read block (indir 2 2) failed. **\n");
- return (-1);
- }
- indir2_blkno =
- __le32_to_cpu (indir1_block[rblock / perblock]) << log2_blksz;
- }
- blknr = __le32_to_cpu (indir2_block[rblock % perblock]);
- }
- /* Tripple indirect. */
- else {
- printf ("** ext2fs doesn't support tripple indirect blocks. **\n");
- return (-1);
- }
-#ifdef DEBUG
- printf ("ext2fs_read_block %08x\n", blknr);
-#endif
- return (blknr);
-}
-
-
int ext2fs_read_file
- (ext2fs_node_t node, int pos, unsigned int len, char *buf) {
+ (struct ext2fs_node *node, int pos, unsigned int len, char *buf)
+{
int i;
int blockcnt;
int log2blocksize = LOG2_EXT2_BLOCK_SIZE (node->data);
@@ -409,8 +127,7 @@ int ext2fs_read_file
int blockend = blocksize;
int skipfirst = 0;
-
- blknr = ext2fs_read_block (node, i);
+ blknr = read_allocated_block(&(node->inode), i);
if (blknr < 0) {
return (-1);
}
@@ -449,8 +166,8 @@ int ext2fs_read_file
return (len);
}
-
-static int ext2fs_iterate_dir (ext2fs_node_t dir, char *name, ext2fs_node_t * fnode, int *ftype)
+int ext2fs_iterate_dir(struct ext2fs_node *dir, char *name,
+ struct ext2fs_node **fnode, int *ftype)
{
unsigned int fpos = 0;
int status;
@@ -479,7 +196,7 @@ static int ext2fs_iterate_dir (ext2fs_node_t dir, char *name, ext2fs_node_t * fn
}
if (dirent.namelen != 0) {
char filename[dirent.namelen + 1];
- ext2fs_node_t fdiro;
+ struct ext2fs_node *fdiro;
int type = FILETYPE_UNKNOWN;
status = ext2fs_read_file (diro,
@@ -581,8 +298,8 @@ static int ext2fs_iterate_dir (ext2fs_node_t dir, char *name, ext2fs_node_t * fn
return (0);
}
-
-static char *ext2fs_read_symlink (ext2fs_node_t node) {
+static char *ext2fs_read_symlink(struct ext2fs_node *node)
+{
char *symlink;
struct ext2fs_node *diro = node;
int status;
@@ -617,17 +334,17 @@ static char *ext2fs_read_symlink (ext2fs_node_t node) {
return (symlink);
}
-
int ext2fs_find_file1
- (const char *currpath,
- ext2fs_node_t currroot, ext2fs_node_t * currfound, int *foundtype) {
+ (const char *currpath, struct ext2fs_node *currroot,
+ struct ext2fs_node **currfound, int *foundtype)
+{
char fpath[strlen (currpath) + 1];
char *name = fpath;
char *next;
int status;
int type = FILETYPE_DIRECTORY;
- ext2fs_node_t currnode = currroot;
- ext2fs_node_t oldnode = currroot;
+ struct ext2fs_node *currnode = currroot;
+ struct ext2fs_node *oldnode = currroot;
strncpy (fpath, currpath, strlen (currpath) + 1);
@@ -721,14 +438,13 @@ int ext2fs_find_file1
return (-1);
}
-
int ext2fs_find_file
- (const char *path,
- ext2fs_node_t rootnode, ext2fs_node_t * foundnode, int expecttype) {
+ (const char *path, struct ext2fs_node *rootnode,
+ struct ext2fs_node **foundnode, int expecttype)
+{
int status;
int foundtype = FILETYPE_DIRECTORY;
-
symlinknest = 0;
if (!path) {
return (0);
@@ -748,9 +464,8 @@ int ext2fs_find_file
return (1);
}
-
int ext2fs_ls (const char *dirname) {
- ext2fs_node_t dirnode;
+ struct ext2fs_node *dirnode;
int status;
if (ext2fs_root == NULL) {
@@ -768,9 +483,8 @@ int ext2fs_ls (const char *dirname) {
return (0);
}
-
int ext2fs_open (const char *filename) {
- ext2fs_node_t fdiro = NULL;
+ struct ext2fs_node *fdiro = NULL;
int status;
int len;
@@ -799,7 +513,6 @@ fail:
return (-1);
}
-
int ext2fs_close (void
) {
if ((ext2fs_file != NULL) && (ext2fs_root != NULL)) {
@@ -825,7 +538,6 @@ int ext2fs_close (void
return (0);
}
-
int ext2fs_read (char *buf, unsigned len) {
int status;
@@ -836,12 +548,10 @@ int ext2fs_read (char *buf, unsigned len) {
if (ext2fs_file == NULL) {
return (0);
}
-
status = ext2fs_read_file (ext2fs_file, 0, len, buf);
return (status);
}
-
int ext2fs_mount (unsigned part_length) {
struct ext2_data *data;
int status;
@@ -880,7 +590,7 @@ int ext2fs_mount (unsigned part_length) {
}
ext2fs_root = data;
-
+ ext4fs_root = data;
return (1);
fail:
diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile
new file mode 100644
index 0000000..850f821
--- /dev/null
+++ b/fs/ext4/Makefile
@@ -0,0 +1,51 @@
+#
+# (C) Copyright 2006
+# Wolfgang Denk, DENX Software Engineering, wd(a)denx.de.
+#
+# (C) Copyright 2003
+# Pavel Bartusek, Sysgo Real-Time Solutions AG, pba(a)sysgo.de
+#
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)libext4fs.o
+
+AOBJS =
+COBJS-$(CONFIG_CMD_EXT4) := ext4fs.o ext4_common.o
+
+SRCS := $(AOBJS:.o=.S) $(COBJS-y:.o=.c)
+OBJS := $(addprefix $(obj),$(AOBJS) $(COBJS-y))
+
+
+all: $(LIB) $(AOBJS)
+
+$(LIB): $(obj).depend $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c
new file mode 100644
index 0000000..6f9351c
--- /dev/null
+++ b/fs/ext4/ext4_common.c
@@ -0,0 +1,573 @@
+/*
+ * (C) Copyright 2011 Samsung Electronics
+ * EXT4 filesystem implementation in Uboot by
+ * Uma Shankar <uma.shankar(a)samsung.com>
+ * Manjunatha C Achar <a.manjunatha(a)samsung.com>
+ *
+ * Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+ * 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.
+ */
+
+/*
+ * ext4load - based on code from GRUB2 fs/ext2.c
+*/
+#include <common.h>
+#include <ext_common.h>
+#include <ext4fs.h>
+#include <malloc.h>
+#include <asm/byteorder.h>
+#include <linux/stat.h>
+#include <linux/time.h>
+#include "ext4_common.h"
+
+struct ext2_data *ext4fs_root;
+struct ext2fs_node *ext4fs_file;
+uint32_t *ext4fs_indir1_block;
+int ext4fs_indir1_size;
+int ext4fs_indir1_blkno = -1;
+uint32_t *ext4fs_indir2_block;
+int ext4fs_indir2_size;
+int ext4fs_indir2_blkno = -1;
+
+uint32_t *ext4fs_indir3_block;
+int ext4fs_indir3_size;
+int ext4fs_indir3_blkno = -1;
+struct ext2_inode *g_parent_inode;
+
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+void *xmalloc(size_t size)
+{
+ void *ptr = malloc(size);
+ if (ptr == NULL && size != 0)
+ printf("bb_msg_memory_exhausted\n");
+ return ptr;
+}
+
+void *xzalloc(size_t size)
+{
+ void *ptr = xmalloc(size);
+ memset(ptr, 0, size);
+ return ptr;
+}
+
+static struct ext4_extent_header *ext4fs_find_leaf(struct ext2_data *data,
+ char *buf, struct ext4_extent_header *ext_block, uint32_t fileblock)
+{
+ struct ext4_extent_idx *index;
+ unsigned long long block;
+ int i;
+
+ while (1) {
+ index = (struct ext4_extent_idx *)(ext_block + 1);
+
+ if (le32_to_cpu(ext_block->magic) != EXT4_EXT_MAGIC)
+ return 0;
+
+ if (ext_block->depth == 0)
+ return ext_block;
+
+ for (i = 0; i < le32_to_cpu(ext_block->entries); i++) {
+ if (fileblock < le32_to_cpu(index[i].block))
+ break;
+ }
+
+ if (--i < 0)
+ return 0;
+
+ block = le32_to_cpu(index[i].leaf_hi);
+ block = (block << 32) + le32_to_cpu(index[i].leaf);
+
+ if (ext2fs_devread(block << LOG2_EXT2_BLOCK_SIZE(data),
+ 0, EXT2_BLOCK_SIZE(data), buf)) {
+ ext_block = (struct ext4_extent_header *)buf;
+ return ext_block;
+ } else
+ return 0;
+ }
+}
+
+static int ext4fs_blockgroup
+ (struct ext2_data *data, int group, struct ext2_block_group *blkgrp)
+{
+ long int blkno;
+ unsigned int blkoff, desc_per_blk;
+
+ desc_per_blk = EXT2_BLOCK_SIZE(data) / sizeof(struct ext2_block_group);
+
+ blkno = __le32_to_cpu(data->sblock.first_data_block) + 1
+ + group / desc_per_blk;
+ blkoff = (group % desc_per_blk) * sizeof(struct ext2_block_group);
+
+ debug("ext4fs read %d group descriptor (blkno %ld blkoff %u)\n",
+ group, blkno, blkoff);
+
+ return ext2fs_devread(blkno << LOG2_EXT2_BLOCK_SIZE(data),
+ blkoff, sizeof(struct ext2_block_group), (char *)blkgrp);
+}
+
+int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode)
+{
+ struct ext2_block_group blkgrp;
+ struct ext2_sblock *sblock = &data->sblock;
+ struct ext_filesystem *fs = get_fs();
+ int inodes_per_block, status;
+ long int blkno;
+ unsigned int blkoff;
+
+ /* It is easier to calculate if the first inode is 0. */
+ ino--;
+ status = ext4fs_blockgroup(data, ino / __le32_to_cpu
+ (sblock->inodes_per_group), &blkgrp);
+
+ if (status == 0)
+ return 0;
+
+ inodes_per_block = EXT2_BLOCK_SIZE(data) / fs->inodesz;
+
+ blkno = __le32_to_cpu(blkgrp.inode_table_id) +
+ (ino % __le32_to_cpu(sblock->inodes_per_group))
+ / inodes_per_block;
+ blkoff = (ino % inodes_per_block) * fs->inodesz;
+ /* Read the inode. */
+ status = ext2fs_devread(blkno << LOG2_EXT2_BLOCK_SIZE(data), blkoff,
+ sizeof(struct ext2_inode), (char *)inode);
+ if (status == 0)
+ return 0;
+
+ return 1;
+}
+
+long int read_allocated_block(struct ext2_inode *inode, int fileblock)
+{
+ long int blknr;
+ int blksz;
+ int log2_blksz;
+ int status;
+ long int rblock;
+ long int perblock_parent;
+ long int perblock_child;
+ unsigned long long start;
+ /*get the blocksize of the filesystem */
+ blksz = EXT2_BLOCK_SIZE(ext4fs_root);
+ log2_blksz = LOG2_EXT2_BLOCK_SIZE(ext4fs_root);
+
+ if (le32_to_cpu(inode->flags) & EXT4_EXTENTS_FLAG) {
+ char buf[EXT2_BLOCK_SIZE(ext4fs_root)];
+ struct ext4_extent_header *leaf;
+ struct ext4_extent *ext;
+ int i;
+
+ leaf = ext4fs_find_leaf(ext4fs_root, buf,
+ (struct ext4_extent_header *)inode->
+ b.blocks.dir_blocks, fileblock);
+ if (!leaf) {
+ printf("invalid extent\n");
+ return -1;
+ }
+
+ ext = (struct ext4_extent *)(leaf + 1);
+
+ for (i = 0; i < le32_to_cpu(leaf->entries); i++) {
+ if (fileblock < le32_to_cpu(ext[i].block))
+ break;
+ }
+
+ if (--i >= 0) {
+ fileblock -= le32_to_cpu(ext[i].block);
+ if (fileblock >= le32_to_cpu(ext[i].len)) {
+ return 0;
+ } else {
+ start = le32_to_cpu(ext[i].start_hi);
+ start = (start << 32) +
+ le32_to_cpu(ext[i].start);
+ return fileblock + start;
+ }
+ } else {
+ printf("something wrong with extent\n");
+ return -1;
+ }
+ }
+
+ /* Direct blocks. */
+ if (fileblock < INDIRECT_BLOCKS)
+ blknr = __le32_to_cpu(inode->b.blocks.dir_blocks[fileblock]);
+
+ /* Indirect. */
+ else if (fileblock < (INDIRECT_BLOCKS + (blksz / 4))) {
+ if (ext4fs_indir1_block == NULL) {
+ ext4fs_indir1_block = (uint32_t *) malloc(blksz);
+ if (ext4fs_indir1_block == NULL) {
+ printf("** SI ext2fs read block (indir 1)"
+ "malloc failed. **\n");
+ return -1;
+ }
+ ext4fs_indir1_size = blksz;
+ ext4fs_indir1_blkno = -1;
+ }
+ if (blksz != ext4fs_indir1_size) {
+ free(ext4fs_indir1_block);
+ ext4fs_indir1_block = NULL;
+ ext4fs_indir1_size = 0;
+ ext4fs_indir1_blkno = -1;
+ ext4fs_indir1_block = (uint32_t *) malloc(blksz);
+ if (ext4fs_indir1_block == NULL) {
+ printf("** SI ext2fs read block (indir 1):"
+ "malloc failed. **\n");
+ return -1;
+ }
+ ext4fs_indir1_size = blksz;
+ }
+ if ((__le32_to_cpu(inode->b.blocks.indir_block) <<
+ log2_blksz) != ext4fs_indir1_blkno) {
+ status = ext2fs_devread(__le32_to_cpu(inode->b.blocks.
+ indir_block) << log2_blksz, 0, blksz,
+ (char *) ext4fs_indir1_block);
+ if (status == 0) {
+ printf("** SI ext2fs read block (indir 1)"
+ "failed. **\n");
+ return 0;
+ }
+ ext4fs_indir1_blkno =
+ __le32_to_cpu(inode->b.blocks.
+ indir_block) << log2_blksz;
+ }
+ blknr = __le32_to_cpu(ext4fs_indir1_block
+ [fileblock - INDIRECT_BLOCKS]);
+ }
+ /* Double indirect. */
+ else if (fileblock <
+ (INDIRECT_BLOCKS + (blksz / 4 * (blksz / 4 + 1)))) {
+
+ long int perblock = blksz / 4;
+ long int rblock = fileblock - (INDIRECT_BLOCKS + blksz / 4);
+
+ if (ext4fs_indir1_block == NULL) {
+ ext4fs_indir1_block = (uint32_t *) malloc(blksz);
+ if (ext4fs_indir1_block == NULL) {
+ printf("** DI ext2fs read block (indir 2 1)"
+ "malloc failed. **\n");
+ return -1;
+ }
+ ext4fs_indir1_size = blksz;
+ ext4fs_indir1_blkno = -1;
+ }
+ if (blksz != ext4fs_indir1_size) {
+ free(ext4fs_indir1_block);
+ ext4fs_indir1_block = NULL;
+ ext4fs_indir1_size = 0;
+ ext4fs_indir1_blkno = -1;
+ ext4fs_indir1_block = (uint32_t *) malloc(blksz);
+ if (ext4fs_indir1_block == NULL) {
+ printf("** DI ext2fs read block (indir 2 1)"
+ "malloc failed. **\n");
+ return -1;
+ }
+ ext4fs_indir1_size = blksz;
+ }
+ if ((__le32_to_cpu(inode->b.blocks.double_indir_block) <<
+ log2_blksz) != ext4fs_indir1_blkno) {
+ status = ext2fs_devread(__le32_to_cpu(inode->b.blocks.
+ double_indir_block) << log2_blksz, 0, blksz,
+ (char *) ext4fs_indir1_block);
+ if (status == 0) {
+ printf("** DI ext2fs read block (indir 2 1)"
+ "failed. **\n");
+ return -1;
+ }
+ ext4fs_indir1_blkno =
+ __le32_to_cpu(inode->b.blocks.
+ double_indir_block) << log2_blksz;
+ }
+
+ if (ext4fs_indir2_block == NULL) {
+ ext4fs_indir2_block = (uint32_t *) malloc(blksz);
+ if (ext4fs_indir2_block == NULL) {
+ printf("** DI ext2fs read block (indir 2 2)"
+ "malloc failed. **\n");
+ return -1;
+ }
+ ext4fs_indir2_size = blksz;
+ ext4fs_indir2_blkno = -1;
+ }
+ if (blksz != ext4fs_indir2_size) {
+ free(ext4fs_indir2_block);
+ ext4fs_indir2_block = NULL;
+ ext4fs_indir2_size = 0;
+ ext4fs_indir2_blkno = -1;
+ ext4fs_indir2_block = (uint32_t *) malloc(blksz);
+ if (ext4fs_indir2_block == NULL) {
+ printf("** DI ext2fs read block (indir 2 2)"
+ "malloc failed. **\n");
+ return -1;
+ }
+ ext4fs_indir2_size = blksz;
+ }
+ if ((__le32_to_cpu(ext4fs_indir1_block[rblock / perblock]) <<
+ log2_blksz) != ext4fs_indir2_blkno) {
+ status = ext2fs_devread(__le32_to_cpu
+ (ext4fs_indir1_block
+ [rblock / perblock]) << log2_blksz,
+ 0, blksz, (char *) ext4fs_indir2_block);
+ if (status == 0) {
+ printf("** DI ext2fs read block (indir 2 2)"
+ "failed. **\n");
+ return -1;
+ }
+ ext4fs_indir2_blkno =
+ __le32_to_cpu(ext4fs_indir1_block[rblock
+ / perblock]) << log2_blksz;
+ }
+ blknr = __le32_to_cpu(ext4fs_indir2_block[rblock % perblock]);
+ }
+ /* Tripple indirect. */
+ else {
+ rblock = fileblock - (INDIRECT_BLOCKS + blksz / 4 +
+ (blksz / 4 * blksz / 4));
+ perblock_child = blksz / 4;
+ perblock_parent = ((blksz / 4) * (blksz / 4));
+
+ if (ext4fs_indir1_block == NULL) {
+ ext4fs_indir1_block = (uint32_t *) malloc(blksz);
+ if (ext4fs_indir1_block == NULL) {
+ printf("** TI ext2fs read block (indir 2 1)"
+ "malloc failed. **\n");
+ return -1;
+ }
+ ext4fs_indir1_size = blksz;
+ ext4fs_indir1_blkno = -1;
+ }
+ if (blksz != ext4fs_indir1_size) {
+ free(ext4fs_indir1_block);
+ ext4fs_indir1_block = NULL;
+ ext4fs_indir1_size = 0;
+ ext4fs_indir1_blkno = -1;
+ ext4fs_indir1_block = (uint32_t *) malloc(blksz);
+ if (ext4fs_indir1_block == NULL) {
+ printf("** TI ext2fs read block (indir 2 1)"
+ "malloc failed. **\n");
+ return -1;
+ }
+ ext4fs_indir1_size = blksz;
+ }
+ if ((__le32_to_cpu(inode->b.blocks.tripple_indir_block) <<
+ log2_blksz) != ext4fs_indir1_blkno) {
+ status = ext2fs_devread
+ (__le32_to_cpu(inode->b.blocks.
+ tripple_indir_block) << log2_blksz,
+ 0, blksz, (char *) ext4fs_indir1_block);
+ if (status == 0) {
+ printf("** TI ext2fs read block (indir 2 1)"
+ "failed. **\n");
+ return -1;
+ }
+ ext4fs_indir1_blkno =
+ __le32_to_cpu(inode->b.blocks.
+ tripple_indir_block) << log2_blksz;
+ }
+
+ if (ext4fs_indir2_block == NULL) {
+ ext4fs_indir2_block = (uint32_t *) malloc(blksz);
+ if (ext4fs_indir2_block == NULL) {
+ printf("** TI ext2fs read block (indir 2 2)"
+ "malloc failed. **\n");
+ return -1;
+ }
+ ext4fs_indir2_size = blksz;
+ ext4fs_indir2_blkno = -1;
+ }
+ if (blksz != ext4fs_indir2_size) {
+ free(ext4fs_indir2_block);
+ ext4fs_indir2_block = NULL;
+ ext4fs_indir2_size = 0;
+ ext4fs_indir2_blkno = -1;
+ ext4fs_indir2_block = (uint32_t *) malloc(blksz);
+ if (ext4fs_indir2_block == NULL) {
+ printf("** TI ext2fs read block (indir 2 2)"
+ "malloc failed. **\n");
+ return -1;
+ }
+ ext4fs_indir2_size = blksz;
+ }
+ if ((__le32_to_cpu(ext4fs_indir1_block[rblock /
+ perblock_parent]) << log2_blksz)
+ != ext4fs_indir2_blkno) {
+ status = ext2fs_devread(__le32_to_cpu
+ (ext4fs_indir1_block
+ [rblock / perblock_parent]) << log2_blksz,
+ 0, blksz, (char *) ext4fs_indir2_block);
+ if (status == 0) {
+ printf("** TI ext2fs read block (indir 2 2)"
+ "failed. **\n");
+ return -1;
+ }
+ ext4fs_indir2_blkno =
+ __le32_to_cpu(ext4fs_indir1_block[rblock /
+ perblock_parent]) << log2_blksz;
+ }
+
+ if (ext4fs_indir3_block == NULL) {
+ ext4fs_indir3_block = (uint32_t *) malloc(blksz);
+ if (ext4fs_indir3_block == NULL) {
+ printf("** TI ext2fs read block (indir 2 2)"
+ "malloc failed. **\n");
+ return -1;
+ }
+ ext4fs_indir3_size = blksz;
+ ext4fs_indir3_blkno = -1;
+ }
+ if (blksz != ext4fs_indir3_size) {
+ free(ext4fs_indir3_block);
+ ext4fs_indir3_block = NULL;
+ ext4fs_indir3_size = 0;
+ ext4fs_indir3_blkno = -1;
+ ext4fs_indir3_block = (uint32_t *) malloc(blksz);
+ if (ext4fs_indir3_block == NULL) {
+ printf("** TI ext2fs read block (indir 2 2)"
+ "malloc failed. **\n");
+ return -1;
+ }
+ ext4fs_indir3_size = blksz;
+ }
+ if ((__le32_to_cpu(ext4fs_indir2_block[rblock
+ / perblock_child]) << log2_blksz) != ext4fs_indir3_blkno){
+ status = ext2fs_devread(__le32_to_cpu
+ (ext4fs_indir2_block[(rblock / perblock_child)
+ % (blksz / 4)]) << log2_blksz,
+ 0, blksz, (char *) ext4fs_indir3_block);
+ if (status == 0) {
+ printf("** TI ext2fs read block (indir 2 2)"
+ "failed. **\n");
+ return -1;
+ }
+ ext4fs_indir3_blkno =
+ __le32_to_cpu(ext4fs_indir2_block[(rblock /
+ perblock_child) % (blksz / 4)]) << log2_blksz;
+ }
+
+ blknr = __le32_to_cpu(ext4fs_indir3_block
+ [rblock % perblock_child]);
+ }
+ debug("ext4fs_read_block %ld\n", blknr);
+ return blknr;
+}
+
+int ext4fs_close(void)
+{
+ if ((ext4fs_file != NULL) && (ext4fs_root != NULL)) {
+ ext4fs_free_node(ext4fs_file, &ext4fs_root->diropen);
+ ext4fs_file = NULL;
+ }
+ if (ext4fs_root != NULL) {
+ free(ext4fs_root);
+ ext4fs_root = NULL;
+ }
+ if (ext4fs_indir1_block != NULL) {
+ free(ext4fs_indir1_block);
+ ext4fs_indir1_block = NULL;
+ ext4fs_indir1_size = 0;
+ ext4fs_indir1_blkno = -1;
+ }
+ if (ext4fs_indir2_block != NULL) {
+ free(ext4fs_indir2_block);
+ ext4fs_indir2_block = NULL;
+ ext4fs_indir2_size = 0;
+ ext4fs_indir2_blkno = -1;
+ }
+ return 0;
+}
+
+int ext4fs_open(const char *filename)
+{
+ struct ext2fs_node *fdiro = NULL;
+ int status;
+ int len;
+
+ if (ext4fs_root == NULL)
+ return -1;
+
+ ext4fs_file = NULL;
+ status = ext2fs_find_file(filename, &ext4fs_root->diropen, &fdiro,
+ FILETYPE_REG);
+ if (status == 0)
+ goto fail;
+
+ if (!fdiro->inode_read) {
+ status = ext4fs_read_inode(fdiro->data, fdiro->ino,
+ &fdiro->inode);
+ if (status == 0)
+ goto fail;
+ }
+ len = __le32_to_cpu(fdiro->inode.size);
+ ext4fs_file = fdiro;
+ return len;
+
+fail:
+ ext4fs_free_node(fdiro, &ext4fs_root->diropen);
+ return -1;
+}
+
+int ext4fs_mount(unsigned part_length)
+{
+ struct ext2_data *data;
+ int status;
+ struct ext_filesystem *fs = get_fs();
+ data = malloc(sizeof(struct ext2_data));
+ if (!data)
+ return 0;
+
+ /* Read the superblock. */
+ status = ext2fs_devread(1 * 2, 0, sizeof(struct ext2_sblock),
+ (char *)&data->sblock);
+
+ if (status == 0)
+ goto fail;
+
+ /* Make sure this is an ext2 filesystem. */
+ if (__le16_to_cpu(data->sblock.magic) != EXT2_MAGIC)
+ goto fail;
+
+ if (__le32_to_cpu(data->sblock.revision_level == 0))
+ fs->inodesz = 128;
+ else
+ fs->inodesz = __le16_to_cpu(data->sblock.inode_size);
+
+#ifdef DEBUG
+ printf("EXT2 rev %d, inode_size %d\n",
+ __le32_to_cpu(data->sblock.revision_level), fs->inodesz);
+#endif
+ data->diropen.data = data;
+ data->diropen.ino = 2;
+ data->diropen.inode_read = 1;
+ data->inode = &data->diropen.inode;
+
+ status = ext4fs_read_inode(data, 2, data->inode);
+ if (status == 0)
+ goto fail;
+
+ inode_size = fs->inodesz;
+ ext4fs_root = data;
+ ext2fs_root = data;
+ return 1;
+
+fail:
+ printf("Failed to mount ext2 filesystem...\n");
+ free(data);
+
+ ext4fs_root = NULL;
+ return 0;
+}
diff --git a/fs/ext4/ext4_common.h b/fs/ext4/ext4_common.h
new file mode 100644
index 0000000..73f218d
--- /dev/null
+++ b/fs/ext4/ext4_common.h
@@ -0,0 +1,44 @@
+/*
+ * (C) Copyright 2011 Samsung Electronics
+ * EXT4 filesystem implementation in Uboot by
+ * Uma Shankar <uma.shankar(a)samsung.com>
+ * Manjunatha C Achar <a.manjunatha(a)samsung.com>
+ *
+ * Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+ * 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_COMMON__
+#define __EXT4_COMMON__
+#include <ext_common.h>
+#include <ext4fs.h>
+
+#define YES 1
+#define NO 0
+#define TRUE 1
+#define FALSE 0
+#define RECOVER 1
+#define SCAN 0
+
+#define S_IFLNK 0120000 /* symbolic link */
+#define BLOCK_NO_ONE 1
+#define SUPERBLOCK_SECTOR 2
+#define SUPERBLOCK_SIZE 1024
+#define F_FILE 1
+
+extern unsigned long part_offset;
+int ext4fs_read_inode(struct ext2_data *data, int ino,
+ struct ext2_inode *inode);
+#endif
diff --git a/fs/ext4/ext4fs.c b/fs/ext4/ext4fs.c
new file mode 100644
index 0000000..d4faa16
--- /dev/null
+++ b/fs/ext4/ext4fs.c
@@ -0,0 +1,215 @@
+/*
+ * (C) Copyright 2011 Samsung Electronics
+ * EXT4 filesystem implementation in Uboot by
+ * Uma Shankar <uma.shankar(a)samsung.com>
+ * Manjunatha C Achar <a.manjunatha(a)samsung.com>
+ *
+ * Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+ * 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.
+ */
+
+/*
+ * ext4load - based on code from GRUB2 fs/ext2.c
+*/
+#include <common.h>
+#include <malloc.h>
+#include <asm/byteorder.h>
+#include <linux/stat.h>
+#include <linux/time.h>
+#include <ext_common.h>
+#include <ext4fs.h>
+#include "ext4_common.h"
+
+int ext4fs_symlinknest;
+block_dev_desc_t *ext4_dev_desc;
+
+struct ext_filesystem *get_fs(void)
+{
+ if (ext4_dev_desc == NULL || ext4_dev_desc->priv == NULL)
+ printf("Invalid Input Arguments %s\n", __func__);
+ return (struct ext_filesystem *)ext4_dev_desc->priv;
+}
+
+int init_fs(block_dev_desc_t *dev_desc)
+{
+ struct ext_filesystem *fs;
+ if (dev_desc == NULL) {
+ printf("Invalid Input Arguments %s\n", __func__);
+ return -1;
+ }
+
+ fs = (struct ext_filesystem *)xzalloc(sizeof(struct ext_filesystem));
+ if (fs == NULL) {
+ printf("malloc failed: %s\n", __func__);
+ return -1;
+ }
+
+ fs->dev_desc = dev_desc;
+ dev_desc->priv = fs;
+ return 0;
+}
+
+void deinit_fs(block_dev_desc_t *dev_desc)
+{
+ if (dev_desc == NULL) {
+ printf("Invalid Input Arguments %s\n", __func__);
+ return;
+ }
+ if (dev_desc->priv)
+ free(dev_desc->priv);
+ return;
+}
+
+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, int pos,
+ unsigned int len, char *buf)
+{
+ int i;
+ int blockcnt;
+ int log2blocksize = LOG2_EXT2_BLOCK_SIZE(node->data);
+ int blocksize = 1 << (log2blocksize + DISK_SECTOR_BITS);
+ unsigned int filesize = __le32_to_cpu(node->inode.size);
+ int previous_block_number = -1;
+ int delayed_start = 0;
+ int delayed_extent = 0;
+ int delayed_skipfirst = 0;
+ int delayed_next = 0;
+ char *delayed_buf = NULL;
+ short status;
+
+ /* Adjust len so it we can't read past the end of the file. */
+ if (len > filesize)
+ len = filesize;
+
+ blockcnt = ((len + pos) + blocksize - 1) / blocksize;
+
+ for (i = pos / blocksize; i < blockcnt; i++) {
+ int blknr;
+ int blockoff = pos % blocksize;
+ int blockend = blocksize;
+ int skipfirst = 0;
+ blknr = read_allocated_block(&(node->inode), i);
+ if (blknr < 0)
+ return -1;
+
+ blknr = blknr << log2blocksize;
+
+ /* Last block. */
+ if (i == blockcnt - 1) {
+ blockend = (len + pos) % blocksize;
+
+ /* The last portion is exactly blocksize. */
+ if (!blockend)
+ blockend = blocksize;
+ }
+
+ /* First block. */
+ if (i == 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 >> SECTOR_BITS;
+ } else { /* spill */
+ status = ext2fs_devread(delayed_start,
+ delayed_skipfirst,
+ delayed_extent,
+ delayed_buf);
+ if (status == 0)
+ return -1;
+ previous_block_number = blknr;
+ delayed_start = blknr;
+ delayed_extent = blockend;
+ delayed_skipfirst = skipfirst;
+ delayed_buf = buf;
+ delayed_next = blknr +
+ (blockend >> SECTOR_BITS);
+ }
+ } else {
+ previous_block_number = blknr;
+ delayed_start = blknr;
+ delayed_extent = blockend;
+ delayed_skipfirst = skipfirst;
+ delayed_buf = buf;
+ delayed_next = blknr +
+ (blockend >> SECTOR_BITS);
+ }
+ } else {
+ if (previous_block_number != -1) {
+ /* spill */
+ status = ext2fs_devread(delayed_start,
+ delayed_skipfirst,
+ delayed_extent,
+ delayed_buf);
+ if (status == 0)
+ return -1;
+ previous_block_number = -1;
+ }
+ memset(buf, 0, blocksize - skipfirst);
+ }
+ buf += blocksize - skipfirst;
+ }
+ if (previous_block_number != -1) {
+ /* spill */
+ status = ext2fs_devread(delayed_start,
+ delayed_skipfirst, delayed_extent,
+ delayed_buf);
+ if (status == 0)
+ return -1;
+ previous_block_number = -1;
+ }
+ return len;
+}
+
+int ext4fs_ls(const char *dirname)
+{
+ struct ext2fs_node *dirnode;
+ int status;
+
+ if (dirname == NULL)
+ return 0;
+
+ status = ext2fs_find_file(dirname, &ext4fs_root->diropen, &dirnode,
+ FILETYPE_DIRECTORY);
+ if (status != 1) {
+ printf("** Can not find directory. **\n");
+ return 1;
+ }
+
+ ext2fs_iterate_dir(dirnode, NULL, NULL, NULL);
+ ext4fs_free_node(dirnode, &ext4fs_root->diropen);
+ return 0;
+}
+
+int ext4fs_read(char *buf, unsigned len)
+{
+ if (ext4fs_root == NULL || ext4fs_file == NULL)
+ return 0;
+ return ext4fs_read_file(ext4fs_file, 0, len, buf);
+}
diff --git a/include/ext2fs.h b/include/ext2fs.h
index 163a9bb..7d4834c 100644
--- a/include/ext2fs.h
+++ b/include/ext2fs.h
@@ -25,6 +25,8 @@
* from the original ext2 fs code, as found in the linux kernel.
*/
+#ifndef __EXT2__
+#define __EXT2__
#define SECTOR_SIZE 0x200
#define SECTOR_BITS 9
@@ -68,14 +70,12 @@ typedef enum
ERR_DEV_NEED_INIT,
ERR_NO_DISK_SPACE,
ERR_NUMBER_OVERFLOW,
-
MAX_ERR_NUM
} ext2fs_error_t;
-
-extern int ext2fs_set_blk_dev(block_dev_desc_t *rbdd, int part);
-extern int ext2fs_ls (const char *dirname);
-extern int ext2fs_open (const char *filename);
-extern int ext2fs_read (char *buf, unsigned len);
-extern int ext2fs_mount (unsigned part_length);
-extern int ext2fs_close(void);
+int ext2fs_ls(const char *dirname);
+int ext2fs_open(const char *filename);
+int ext2fs_read(char *buf, unsigned len);
+int ext2fs_close(void);
+int ext2_register_device(block_dev_desc_t *dev_desc, int part_no);
+#endif
diff --git a/include/ext4fs.h b/include/ext4fs.h
new file mode 100644
index 0000000..fd7bd47
--- /dev/null
+++ b/include/ext4fs.h
@@ -0,0 +1,116 @@
+/*
+ * (C) Copyright 2011 Samsung Electronics
+ * EXT4 filesystem implementation in Uboot by
+ * Uma Shankar <uma.shankar(a)samsung.com>
+ * Manjunatha C Achar <a.manjunatha(a)samsung.com>
+ *
+ * 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.
+ *
+ * Some parts of this code (mainly the structures and defines) are
+ * from the original ext4 fs code, as found in the linux kernel.
+ * Reference for ext4load and ls features have ben taken from GRUB
+ */
+
+#ifndef __EXT4__
+#define __EXT4__
+#include <ext_common.h>
+
+#define EXT4_EXTENTS_FLAG 0x80000
+#define EXT4_EXT_MAGIC 0xf30a
+#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010
+#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040
+#define EXT4_INDIRECT_BLOCKS 12
+
+#define EXT4_BG_INODE_UNINIT 0x0001
+#define EXT4_BG_BLOCK_UNINIT 0x0002
+#define EXT4_BG_INODE_ZEROED 0x0004
+
+struct ext4_extent_header {
+ uint16_t magic;
+ uint16_t entries;
+ uint16_t max;
+ uint16_t depth;
+ uint32_t generation;
+};
+
+struct ext4_extent {
+ uint32_t block;
+ uint16_t len;
+ uint16_t start_hi;
+ uint32_t start;
+};
+
+struct ext4_extent_idx {
+ uint32_t block;
+ uint32_t leaf;
+ uint16_t leaf_hi;
+ uint16_t unused;
+};
+
+struct ext_filesystem {
+ /*Total Sector of partition */
+ uint64_t total_sect;
+ /*Block size of partition */
+ uint32_t blksz;
+ /*Inode size of partition */
+ uint32_t inodesz;
+ /*Sectors per Block */
+ uint32_t sect_perblk;
+ /*Group Descriptor Block Number */
+ uint32_t gdtable_blkno;
+ /*Total block groups of partition */
+ uint32_t no_blkgrp;
+ /*No of blocks required for bgdtable */
+ uint32_t no_blk_pergdt;
+ /*superblock */
+ struct ext2_sblock *sb;
+ /*block group descritpor table */
+ struct ext2_block_group *gd;
+ char *gdtable;
+
+ /*Block Bitmap Related */
+ unsigned char **blk_bmaps;
+ long int curr_blkno;
+ uint16_t first_pass_bbmap;
+
+ /*Inode Bitmap Related */
+ unsigned char **inode_bmaps;
+ int curr_inode_no;
+ uint16_t first_pass_ibmap;
+
+ /*Journal Related */
+
+ /*Block Device Descriptor */
+ block_dev_desc_t *dev_desc;
+};
+
+/*############################*/
+extern block_dev_desc_t *ext4_dev_desc;
+/*#########################*/
+
+extern struct ext2_data *ext4fs_root;
+extern struct ext2fs_node *ext4fs_file;
+struct ext_filesystem *get_fs(void);
+int init_fs(block_dev_desc_t *);
+void deinit_fs(block_dev_desc_t *);
+int ext4fs_open(const char *filename);
+int ext4fs_read(char *buf, unsigned len);
+int ext4fs_mount(unsigned part_length);
+int ext4fs_close(void);
+int ext4fs_ls(const char *dirname);
+void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot);
+extern int ext2fs_devread(int sector, int byte_offset, int byte_len, char *buf);
+extern void *xzalloc(size_t size);
+#endif
diff --git a/include/ext_common.h b/include/ext_common.h
new file mode 100644
index 0000000..8b0474c
--- /dev/null
+++ b/include/ext_common.h
@@ -0,0 +1,199 @@
+/*
+ * (C) Copyright 2011 Samsung Electronics
+ * EXT4 filesystem implementation in Uboot by
+ * Uma Shankar <uma.shankar(a)samsung.com>
+ * Manjunatha C Achar <a.manjunatha(a)samsung.com>
+ *
+ * Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+ * 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.
+ */
+
+
+/* Some parts of this code (mainly the structures and defines) are
+ * from the original ext2 fs code, as found in the linux kernel.
+ */
+
+#ifndef __EXT_COMMON__
+#define __EXT_COMMON__
+
+#define SECTOR_SIZE 0x200
+#define SECTOR_BITS 9
+
+/* Magic value used to identify an ext2 filesystem. */
+#define EXT2_MAGIC 0xEF53
+/* Amount of indirect blocks in an inode. */
+#define INDIRECT_BLOCKS 12
+/* Maximum lenght of a pathname. */
+#define EXT2_PATH_MAX 4096
+/* Maximum nesting of symlinks, used to prevent a loop. */
+#define EXT2_MAX_SYMLINKCNT 8
+
+/* Filetype used in directory entry. */
+#define FILETYPE_UNKNOWN 0
+#define FILETYPE_REG 1
+#define FILETYPE_DIRECTORY 2
+#define FILETYPE_SYMLINK 7
+
+/* Filetype information as used in inodes. */
+#define FILETYPE_INO_MASK 0170000
+#define FILETYPE_INO_REG 0100000
+#define FILETYPE_INO_DIRECTORY 0040000
+#define FILETYPE_INO_SYMLINK 0120000
+#define EXT2_ROOT_INO 2 /* Root inode */
+
+/* Bits used as offset in sector */
+#define DISK_SECTOR_BITS 9
+/* The size of an ext2 block in bytes. */
+#define EXT2_BLOCK_SIZE(data) (1 << LOG2_BLOCK_SIZE(data))
+
+/* Log2 size of ext2 block in 512 blocks. */
+#define LOG2_EXT2_BLOCK_SIZE(data) (__le32_to_cpu \
+ (data->sblock.log2_block_size) + 1)
+
+/* Log2 size of ext2 block in bytes. */
+#define LOG2_BLOCK_SIZE(data) (__le32_to_cpu \
+ (data->sblock.log2_block_size) + 10)
+#define INODE_SIZE_FILESYSTEM(data) (__le32_to_cpu \
+ (data->sblock.inode_size))
+
+#define EXT2_FT_DIR 2
+#define SUCCESS 1
+/*
+ * Macro-instructions used to manage several block sizes
+ */
+#define EXT2_MIN_BLOCK_LOG_SIZE 10 /* 1024 */
+#define EXT2_MAX_BLOCK_LOG_SIZE 16 /* 65536 */
+#define EXT2_MIN_BLOCK_SIZE (1 << EXT2_MIN_BLOCK_LOG_SIZE)
+#define EXT2_MAX_BLOCK_SIZE (1 << EXT2_MAX_BLOCK_LOG_SIZE)
+
+/* The ext2 superblock. */
+struct ext2_sblock {
+ uint32_t total_inodes;
+ uint32_t total_blocks;
+ uint32_t reserved_blocks;
+ uint32_t free_blocks;
+ uint32_t free_inodes;
+ uint32_t first_data_block;
+ uint32_t log2_block_size;
+ uint32_t log2_fragment_size;
+ uint32_t blocks_per_group;
+ uint32_t fragments_per_group;
+ uint32_t inodes_per_group;
+ uint32_t mtime;
+ uint32_t utime;
+ uint16_t mnt_count;
+ uint16_t max_mnt_count;
+ uint16_t magic;
+ uint16_t fs_state;
+ uint16_t error_handling;
+ uint16_t minor_revision_level;
+ uint32_t lastcheck;
+ uint32_t checkinterval;
+ uint32_t creator_os;
+ uint32_t revision_level;
+ uint16_t uid_reserved;
+ uint16_t gid_reserved;
+ uint32_t first_inode;
+ uint16_t inode_size;
+ uint16_t block_group_number;
+ uint32_t feature_compatibility;
+ uint32_t feature_incompat;
+ uint32_t feature_ro_compat;
+ uint32_t unique_id[4];
+ char volume_name[16];
+ char last_mounted_on[64];
+ uint32_t compression_info;
+};
+
+struct ext2_block_group {
+ __u32 block_id; /* Blocks bitmap block */
+ __u32 inode_id; /* Inodes bitmap block */
+ __u32 inode_table_id; /* Inodes table block */
+ __u16 free_blocks; /* Free blocks count */
+ __u16 free_inodes; /* Free inodes count */
+ __u16 used_dir_cnt; /* Directories count */
+ __u16 bg_flags;
+ __u32 bg_reserved[2];
+ __u16 bg_itable_unused; /* Unused inodes count */
+ __u16 bg_checksum; /* crc16(s_uuid+grouo_num+group_desc)*/
+};
+
+/* The ext2 inode. */
+struct ext2_inode {
+ uint16_t mode;
+ uint16_t uid;
+ uint32_t size;
+ uint32_t atime;
+ uint32_t ctime;
+ uint32_t mtime;
+ uint32_t dtime;
+ uint16_t gid;
+ uint16_t nlinks;
+ uint32_t blockcnt; /* Blocks of 512 bytes!! */
+ uint32_t flags;
+ uint32_t osd1;
+ union {
+ struct datablocks {
+ uint32_t dir_blocks[INDIRECT_BLOCKS];
+ uint32_t indir_block;
+ uint32_t double_indir_block;
+ uint32_t tripple_indir_block;
+ } blocks;
+ char symlink[60];
+ } b;
+ uint32_t version;
+ uint32_t acl;
+ uint32_t dir_acl;
+ uint32_t fragment_addr;
+ uint32_t osd2[3];
+};
+
+/* The header of an ext2 directory entry. */
+struct ext2_dirent {
+ uint32_t inode;
+ uint16_t direntlen;
+ uint8_t namelen;
+ uint8_t filetype;
+};
+
+struct ext2fs_node {
+ struct ext2_data *data;
+ struct ext2_inode inode;
+ int ino;
+ int inode_read;
+};
+
+/* Information about a "mounted" ext2 filesystem. */
+struct ext2_data {
+ struct ext2_sblock sblock;
+ struct ext2_inode *inode;
+ struct ext2fs_node diropen;
+};
+
+extern unsigned int inode_size;
+extern struct ext2_data *ext2fs_root;
+extern struct ext2_data *ext4fs_root;
+extern int ext2fs_iterate_dir(struct ext2fs_node *dir, char *name,
+ struct ext2fs_node **fnode, int *ftype);
+extern int ext2fs_find_file(const char *path, struct ext2fs_node *rootnode,
+ struct ext2fs_node **foundnode, int expecttype);
+extern int ext2fs_devread(int sector, int byte_offset, int byte_len, char *buf);
+int ext2fs_set_blk_dev(block_dev_desc_t *rbdd, int part);
+uint32_t div_roundup(uint32_t size, uint32_t n);
+long int read_allocated_block(struct ext2_inode *inode, int fileblock);
+int ext2fs_mount(unsigned part_length);
+void *xmalloc(size_t size);
+void *xzalloc(size_t size);
+#endif
--
1.7.0.4
9
27

[U-Boot] [PATCH v1 0/5] env: handle special variables and selective env default
by Gerlando Falauto 18 Sep '12
by Gerlando Falauto 18 Sep '12
18 Sep '12
This patchset modifies the handling of all the operations on the environment
(set/import/default) so to unify handling of special variables.
On top of that we implement a selective "env default".
A selective "env import" would imply a user API change and should therefore
be discussed separately.
Changes in the syntax (user API):
- "env default" -f: override write-once variables, -a means all
First patch is a cosmetic prerequisite to the second patch
which constifies serial_assign().
Changes from v0:
- checkpatch cleanup
- removed himport_ex()
- removed warning for serial_assign()
- env import NOT implemented here
Gerlando Falauto (5):
serial: cosmetic checkpatch compliance
serial: constify serial_assign()
env: unify logic to check and apply changes
env: check and apply changes on delete/destroy
env: make "env default" selective, check and apply
README | 2 +
common/cmd_nvedit.c | 209 +++++++++++++++++++++++++++++++---------------
common/env_common.c | 35 +++++++-
common/serial.c | 51 ++++++------
include/config_cmd_all.h | 1 +
include/environment.h | 12 +++
include/search.h | 23 +++++-
include/serial.h | 19 ++--
lib/hashtable.c | 61 ++++++++++++--
9 files changed, 300 insertions(+), 113 deletions(-)
8
103
Dear Wolfgang Denk,
please pull the following changes.
Thanks,
Michal
The following changes since commit 99ffccbd3e5b7bc715e2eed6ea6d36f4020b56d8:
Diana CRACIUN (1):
Flush cache after the OS image is loaded into the memory.
are available in the git repository at:
git://www.denx.de/git/u-boot-microblaze.git master
Michal Simek (25):
net: emaclite: Change driver name and add address
net: emaclite: Remove deviceid property
net: emaclite: Use calloc instead of malloc
net: emaclite: Remove baseaddress from xemaclite
net: emaclite: Use dynamic allocation
net: emaclite: Setup RX/TX ping pong for every instance
net: emaclite: Move RX/TX ping pong initialization to board
net: emaclite: Use helper function for io accesses
net: emaclite: Fix coding style
net: emaclite: Use unsigned long for baseaddr
net: emaclite: Use PKTSIZE directly
microblaze: Fix in/out_be8/16/32 functions
microblaze: Support CTRL+C when tftp is running
microblaze: Support flashes on lower addresses
microblaze: Initialize jumptable and console
microblaze: Fix unaligned.h for endians
microblaze: Copy bootfile from variables
microblaze: Remove debug saving value
microblaze: Setup MB vectors if feature is enable for u-boot
microblaze: Save and restore first unused vector
microblaze: Clean up reset asm code
microblaze: Do not select NFS for platforms without ethernet
microblaze: Remove address offset for uart16550
microblaze: Fix no return statement from microblaze-generic board
microblaze: Enable FDT/FIT support
arch/microblaze/cpu/start.S | 66 ++---
arch/microblaze/include/asm/io.h | 33 ++-
arch/microblaze/include/asm/unaligned.h | 17 +--
arch/microblaze/lib/board.c | 17 ++
.../xilinx/microblaze-generic/microblaze-generic.c | 18 +-
drivers/net/xilinx_emaclite.c | 285 +++++++++++---------
include/configs/microblaze-generic.h | 9 +-
include/netdev.h | 3 +-
8 files changed, 251 insertions(+), 197 deletions(-)
--
Michal Simek, Ing. (M.Eng)
w: www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel 2.6 Microblaze Linux - http://www.monstr.eu/fdt/
Microblaze U-BOOT custodian
3
18

[U-Boot] [PATCH] [U-BOOT] Zoom2: Ethernet: Enabling LAN9221 chip and CMD_NET.
by Aldo Brett Cedillo Martinez 06 Sep '12
by Aldo Brett Cedillo Martinez 06 Sep '12
06 Sep '12
Configures GPMC, adds macros to enable net commands, and adds proper
initialization to board_eth_init function.
I have a similar patch to enable ethernet in zoom3 after initial support
patch.
Signed-off-by: Aldo Brett Cedillo Martinez <aldo.cedillo(a)ti.com>
---
board/logicpd/zoom2/zoom2.c | 21 +++++++++++++++++++++
include/configs/omap3_zoom2.h | 10 +++++++++-
2 files changed, 30 insertions(+), 1 deletions(-)
diff --git a/board/logicpd/zoom2/zoom2.c b/board/logicpd/zoom2/zoom2.c
index e9f6625..54d3e9f 100644
--- a/board/logicpd/zoom2/zoom2.c
+++ b/board/logicpd/zoom2/zoom2.c
@@ -60,6 +60,16 @@ static u32 gpmc_serial_TL16CP754C[GPMC_MAX_REG] = {
0x1D0904C4, 0
};
+/* Ethernet GPMC configuration */
+static u32 gpmc_eth[GPMC_MAX_REG] = {
+ NET_GPMC_CONFIG1,
+ NET_GPMC_CONFIG2,
+ NET_GPMC_CONFIG3,
+ NET_GPMC_CONFIG4,
+ NET_GPMC_CONFIG5,
+ NET_GPMC_CONFIG6, 0
+};
+
/* Used to track the revision of the board */
static zoom2_revision revision = ZOOM2_REVISION_UNKNOWN;
@@ -130,6 +140,12 @@ int board_init (void)
enable_gpmc_cs_config(gpmc_config, &gpmc_cfg->cs[3],
SERIAL_TL16CP754C_BASE, GPMC_SIZE_16M);
+#ifdef CONFIG_CMD_NET
+ gpmc_config = gpmc_eth;
+ enable_gpmc_cs_config(gpmc_config, &gpmc_cfg->cs[7],
+ CONFIG_SMC911X_BASE, GPMC_SIZE_16M);
+#endif /* (CONFIG_CMD_NET) */
+
/* board id for Linux */
gd->bd->bi_arch_number = MACH_TYPE_OMAP_ZOOM2;
/* boot param addr */
@@ -186,6 +202,11 @@ int board_eth_init(bd_t *bis)
#ifdef CONFIG_LAN91C96
rc = lan91c96_initialize(0, CONFIG_LAN91C96_BASE);
#endif
+
+#ifdef CONFIG_SMC911X
+ rc = smc911x_initialize(0, CONFIG_SMC911X_BASE);
+#endif
+
return rc;
}
#endif
diff --git a/include/configs/omap3_zoom2.h b/include/configs/omap3_zoom2.h
index eef95fe..c66d571 100644
--- a/include/configs/omap3_zoom2.h
+++ b/include/configs/omap3_zoom2.h
@@ -154,7 +154,7 @@
#undef CONFIG_CMD_FPGA /* FPGA configuration Support */
#undef CONFIG_CMD_IMI /* iminfo */
#undef CONFIG_CMD_IMLS /* List all found images */
-#undef CONFIG_CMD_NET /* bootp, tftpboot, rarpboot */
+#define CONFIG_CMD_NET /* bootp, tftpboot, rarpboot */
#undef CONFIG_CMD_NFS /* NFS support */
#define CONFIG_SYS_NO_FLASH
@@ -165,6 +165,14 @@
#define CONFIG_SYS_I2C_BUS_SELECT 1
#define CONFIG_DRIVER_OMAP34XX_I2C 1
+/* Ethernet */
+#ifdef CONFIG_CMD_NET
+#define CONFIG_NET_MULTI
+#define CONFIG_SMC911X
+#define CONFIG_SMC911X_32_BIT
+#define CONFIG_SMC911X_BASE 0x2C000000
+#endif /* (CONFIG_CMD_NET) */
+
/*
* TWL4030
*/
--
1.6.3.3
3
3

27 Aug '12
All arches init these variables the same way, so move the logic
into the core net code to avoid duplicating it everywhere else.
Signed-off-by: Mike Frysinger <vapier(a)gentoo.org>
---
arch/arm/lib/board.c | 11 -----------
arch/avr32/lib/board.c | 5 -----
arch/blackfin/lib/board.c | 9 +--------
arch/m68k/lib/board.c | 14 --------------
arch/microblaze/lib/board.c | 7 -------
arch/mips/lib/board.c | 11 -----------
arch/nds32/lib/board.c | 9 ---------
arch/nios2/lib/board.c | 2 --
arch/powerpc/lib/board.c | 11 -----------
arch/sandbox/lib/board.c | 3 ---
arch/sh/lib/board.c | 22 ++--------------------
arch/sparc/lib/board.c | 7 -------
arch/x86/lib/board.c | 12 ------------
net/eth.c | 12 ++++++++++++
14 files changed, 15 insertions(+), 120 deletions(-)
diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c
index 3d78274..2c4276b 100644
--- a/arch/arm/lib/board.c
+++ b/arch/arm/lib/board.c
@@ -536,9 +536,6 @@ void board_init_r(gd_t *id, ulong dest_addr)
arm_pci_init();
#endif
- /* IP Address */
- gd->bd->bi_ip_addr = getenv_IPaddr("ipaddr");
-
stdio_init(); /* get the devices list going. */
jumptable_init();
@@ -576,14 +573,6 @@ void board_init_r(gd_t *id, ulong dest_addr)
/* Initialize from environment */
load_addr = getenv_ulong("loadaddr", 16, load_addr);
-#if defined(CONFIG_CMD_NET)
- {
- char *s = getenv("bootfile");
-
- if (s != NULL)
- copy_filename(BootFile, s, sizeof(BootFile));
- }
-#endif
#ifdef CONFIG_BOARD_LATE_INIT
board_late_init();
diff --git a/arch/avr32/lib/board.c b/arch/avr32/lib/board.c
index 63fe297..4bc3c8a 100644
--- a/arch/avr32/lib/board.c
+++ b/arch/avr32/lib/board.c
@@ -304,8 +304,6 @@ void board_init_r(gd_t *new_gd, ulong dest_addr)
/* initialize environment */
env_relocate();
- bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
-
stdio_init();
jumptable_init();
console_init_r();
@@ -317,9 +315,6 @@ void board_init_r(gd_t *new_gd, ulong dest_addr)
bb_miiphy_init();
#endif
#if defined(CONFIG_CMD_NET)
- s = getenv("bootfile");
- if (s)
- copy_filename(BootFile, s, sizeof(BootFile));
puts("Net: ");
eth_initialize(gd->bd);
#endif
diff --git a/arch/blackfin/lib/board.c b/arch/blackfin/lib/board.c
index e3ee4cd..4310fef 100644
--- a/arch/blackfin/lib/board.c
+++ b/arch/blackfin/lib/board.c
@@ -294,15 +294,8 @@ static void board_net_init_r(bd_t *bd)
bb_miiphy_init();
#endif
#ifdef CONFIG_CMD_NET
- char *s;
-
- if ((s = getenv("bootfile")) != NULL)
- copy_filename(BootFile, s, sizeof(BootFile));
-
- bd->bi_ip_addr = getenv_IPaddr("ipaddr");
-
printf("Net: ");
- eth_initialize(gd->bd);
+ eth_initialize(bd);
#endif
}
diff --git a/arch/m68k/lib/board.c b/arch/m68k/lib/board.c
index 259b71c..b3dca77 100644
--- a/arch/m68k/lib/board.c
+++ b/arch/m68k/lib/board.c
@@ -507,15 +507,6 @@ void board_init_r (gd_t *id, ulong dest_addr)
/* relocate environment function pointers etc. */
env_relocate ();
- /*
- * Fill in missing fields of bd_info.
- * We do this here, where we have "normal" access to the
- * environment; we used to do this still running from ROM,
- * where had to use getenv_f(), which can be pretty slow when
- * the environment is in EEPROM.
- */
- bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
-
WATCHDOG_RESET ();
#if defined(CONFIG_PCI)
@@ -568,11 +559,6 @@ void board_init_r (gd_t *id, ulong dest_addr)
/* Initialize from environment */
load_addr = getenv_ulong("loadaddr", 16, load_addr);
-#if defined(CONFIG_CMD_NET)
- if ((s = getenv ("bootfile")) != NULL) {
- copy_filename (BootFile, s, sizeof (BootFile));
- }
-#endif
WATCHDOG_RESET ();
diff --git a/arch/microblaze/lib/board.c b/arch/microblaze/lib/board.c
index 9828b76..f3679d5 100644
--- a/arch/microblaze/lib/board.c
+++ b/arch/microblaze/lib/board.c
@@ -176,19 +176,12 @@ void board_init (void)
load_addr = getenv_ulong("loadaddr", 16, load_addr);
#if defined(CONFIG_CMD_NET)
- /* IP Address */
- bd->bi_ip_addr = getenv_IPaddr("ipaddr");
-
printf("Net: ");
eth_initialize(gd->bd);
uchar enetaddr[6];
eth_getenv_enetaddr("ethaddr", enetaddr);
printf("MAC: %pM\n", enetaddr);
-
- s = getenv("bootfile");
- if (s != NULL)
- copy_filename(BootFile, s, sizeof(BootFile));
#endif
/* main_loop */
diff --git a/arch/mips/lib/board.c b/arch/mips/lib/board.c
index d998f0e..6b36a98 100644
--- a/arch/mips/lib/board.c
+++ b/arch/mips/lib/board.c
@@ -316,9 +316,6 @@ void board_init_r(gd_t *id, ulong dest_addr)
/* relocate environment function pointers etc. */
env_relocate();
- /* IP Address */
- bd->bi_ip_addr = getenv_IPaddr("ipaddr");
-
#if defined(CONFIG_PCI)
/*
* Do pci configuration
@@ -338,14 +335,6 @@ void board_init_r(gd_t *id, ulong dest_addr)
/* Initialize from environment */
load_addr = getenv_ulong("loadaddr", 16, load_addr);
-#if defined(CONFIG_CMD_NET)
- {
- char *s = getenv("bootfile");
-
- if (s != NULL)
- copy_filename(BootFile, s, sizeof(BootFile));
- }
-#endif
#ifdef CONFIG_CMD_SPI
puts("SPI: ");
diff --git a/arch/nds32/lib/board.c b/arch/nds32/lib/board.c
index 66e4537..446e0fd 100644
--- a/arch/nds32/lib/board.c
+++ b/arch/nds32/lib/board.c
@@ -368,9 +368,6 @@ void board_init_r(gd_t *id, ulong dest_addr)
nds32_pci_init();
#endif
- /* IP Address */
- gd->bd->bi_ip_addr = getenv_IPaddr("ipaddr");
-
stdio_init(); /* get the devices list going. */
jumptable_init();
@@ -401,12 +398,6 @@ void board_init_r(gd_t *id, ulong dest_addr)
/* Initialize from environment */
load_addr = getenv_ulong("loadaddr", 16, load_addr);
-#if defined(CONFIG_CMD_NET)
- s = getenv("bootfile");
- if (s != NULL)
- copy_filename(BootFile, s, sizeof(BootFile));
-#endif
-
#ifdef BOARD_LATE_INIT
board_late_init();
#endif
diff --git a/arch/nios2/lib/board.c b/arch/nios2/lib/board.c
index 65de26e..ca8a3e5 100644
--- a/arch/nios2/lib/board.c
+++ b/arch/nios2/lib/board.c
@@ -143,8 +143,6 @@ void board_init (void)
WATCHDOG_RESET ();
env_relocate();
- bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
-
WATCHDOG_RESET ();
stdio_init();
jumptable_init();
diff --git a/arch/powerpc/lib/board.c b/arch/powerpc/lib/board.c
index ff5888e..931b098 100644
--- a/arch/powerpc/lib/board.c
+++ b/arch/powerpc/lib/board.c
@@ -877,9 +877,6 @@ void board_init_r(gd_t *id, ulong dest_addr)
#endif
#endif /* CONFIG_CMD_NET */
- /* IP Address */
- bd->bi_ip_addr = getenv_IPaddr("ipaddr");
-
WATCHDOG_RESET();
#if defined(CONFIG_PCI) && !defined(CONFIG_SYS_EARLY_PCI_INIT)
@@ -935,14 +932,6 @@ void board_init_r(gd_t *id, ulong dest_addr)
/* Initialize from environment */
load_addr = getenv_ulong("loadaddr", 16, load_addr);
-#if defined(CONFIG_CMD_NET)
- {
- char *s = getenv("bootfile");
-
- if (s != NULL)
- copy_filename(BootFile, s, sizeof(BootFile));
- }
-#endif
WATCHDOG_RESET();
diff --git a/arch/sandbox/lib/board.c b/arch/sandbox/lib/board.c
index b7997e9..a71b1ba 100644
--- a/arch/sandbox/lib/board.c
+++ b/arch/sandbox/lib/board.c
@@ -226,9 +226,6 @@ void board_init_r(gd_t *id, ulong dest_addr)
/* initialize environment */
env_relocate();
- /* IP Address */
- gd->bd->bi_ip_addr = getenv_IPaddr("ipaddr");
-
stdio_init(); /* get the devices list going. */
jumptable_init();
diff --git a/arch/sh/lib/board.c b/arch/sh/lib/board.c
index d9c0c22..e1a5739 100644
--- a/arch/sh/lib/board.c
+++ b/arch/sh/lib/board.c
@@ -99,14 +99,6 @@ static int sh_mem_env_init(void)
return 0;
}
-#if defined(CONFIG_CMD_NET)
-static int sh_net_init(void)
-{
- gd->bd->bi_ip_addr = getenv_IPaddr("ipaddr");
- return 0;
-}
-#endif
-
#if defined(CONFIG_CMD_MMC)
static int sh_mmc_init(void)
{
@@ -144,9 +136,6 @@ init_fnc_t *init_sequence[] =
#ifdef CONFIG_BOARD_LATE_INIT
board_late_init,
#endif
-#if defined(CONFIG_CMD_NET)
- sh_net_init, /* SH specific eth init */
-#endif
#if defined(CONFIG_CMD_MMC)
sh_mmc_init,
#endif
@@ -200,15 +189,8 @@ void sh_generic_init(void)
bb_miiphy_init();
#endif
#if defined(CONFIG_CMD_NET)
- {
- char *s;
- puts("Net: ");
- eth_initialize(gd->bd);
-
- s = getenv("bootfile");
- if (s != NULL)
- copy_filename(BootFile, s, sizeof(BootFile));
- }
+ puts("Net: ");
+ eth_initialize(gd->bd);
#endif /* CONFIG_CMD_NET */
while (1) {
diff --git a/arch/sparc/lib/board.c b/arch/sparc/lib/board.c
index 519a4fb..a36f165 100644
--- a/arch/sparc/lib/board.c
+++ b/arch/sparc/lib/board.c
@@ -333,8 +333,6 @@ void board_init_f(ulong bootflag)
mac_read_from_eeprom();
#endif
- /* IP Address */
- bd->bi_ip_addr = getenv_IPaddr("ipaddr");
#if defined(CONFIG_PCI)
/*
* Do pci configuration
@@ -359,11 +357,6 @@ void board_init_f(ulong bootflag)
/* Initialize from environment */
load_addr = getenv_ulong("loadaddr", 16, load_addr);
-#if defined(CONFIG_CMD_NET)
- if ((s = getenv("bootfile")) != NULL) {
- copy_filename(BootFile, s, sizeof(BootFile));
- }
-#endif /* CONFIG_CMD_NET */
WATCHDOG_RESET();
diff --git a/arch/x86/lib/board.c b/arch/x86/lib/board.c
index d742fec..595b3c9 100644
--- a/arch/x86/lib/board.c
+++ b/arch/x86/lib/board.c
@@ -321,12 +321,6 @@ void board_init_r(gd_t *id, ulong dest_addr)
env_relocate();
show_boot_progress(0x26);
-
-#ifdef CONFIG_CMD_NET
- /* IP Address */
- bd_data.bi_ip_addr = getenv_IPaddr("ipaddr");
-#endif
-
#if defined(CONFIG_PCI)
/*
* Do pci configuration
@@ -373,12 +367,6 @@ void board_init_r(gd_t *id, ulong dest_addr)
/* Initialize from environment */
load_addr = getenv_ulong("loadaddr", 16, load_addr);
-#if defined(CONFIG_CMD_NET)
- s = getenv("bootfile");
-
- if (s != NULL)
- copy_filename(BootFile, s, sizeof(BootFile));
-#endif
WATCHDOG_RESET();
diff --git a/net/eth.c b/net/eth.c
index f3a55ba..c5daee1 100644
--- a/net/eth.c
+++ b/net/eth.c
@@ -224,6 +224,16 @@ int eth_register(struct eth_device *dev)
return 0;
}
+static void eth_env_init(bd_t *bis)
+{
+ const char *s;
+
+ if ((s = getenv("bootfile")) != NULL)
+ copy_filename(BootFile, s, sizeof(BootFile));
+
+ bis->bi_ip_addr = getenv_IPaddr("ipaddr");
+}
+
int eth_initialize(bd_t *bis)
{
int num_devices = 0;
@@ -239,6 +249,8 @@ int eth_initialize(bd_t *bis)
phy_init();
#endif
+ eth_env_init(bis);
+
/*
* If board-specific initialization exists, call it.
* If not, call a CPU-specific one
--
1.7.8.3
5
20
From: Uma Shankar <uma.shankar(a)samsung.com>
Signed-off-by: Uma Shankar <uma.shankar(a)samsung.com>
Signed-off-by: Manjunatha C Achar <a.manjunatha(a)samsung.com>
Signed-off-by: Iqbal Shareef <iqbal.ams(a)samsung.com>
Signed-off-by: Hakgoo Lee <goodguy.lee(a)samsung.com>
---
common/cmd_ext4.c | 135 +++++
fs/ext4/Makefile | 2 +-
fs/ext4/crc16.c | 62 +++
fs/ext4/crc16.h | 16 +
fs/ext4/ext4_common.c | 1386 +++++++++++++++++++++++++++++++++++++++++++++++-
fs/ext4/ext4_common.h | 17 +
fs/ext4/ext4_journal.c | 650 +++++++++++++++++++++++
fs/ext4/ext4_journal.h | 147 +++++
fs/ext4/ext4fs.c | 1038 ++++++++++++++++++++++++++++++++++++-
include/ext4fs.h | 8 +
10 files changed, 3457 insertions(+), 4 deletions(-)
create mode 100644 fs/ext4/crc16.c
create mode 100644 fs/ext4/crc16.h
create mode 100644 fs/ext4/ext4_journal.c
create mode 100644 fs/ext4/ext4_journal.h
diff --git a/common/cmd_ext4.c b/common/cmd_ext4.c
index 7c2d541..781c6fe 100644
--- a/common/cmd_ext4.c
+++ b/common/cmd_ext4.c
@@ -47,11 +47,53 @@
uint64_t total_sector;
uint64_t part_offset;
+static unsigned long part_size;
+static int cur_part = 1;
#define DOS_PART_MAGIC_OFFSET 0x1fe
#define DOS_FS_TYPE_OFFSET 0x36
#define DOS_FS32_TYPE_OFFSET 0x52
+static int ext4_register_device(block_dev_desc_t *dev_desc, int part_no)
+{
+ unsigned char buffer[SECTOR_SIZE];
+ disk_partition_t info;
+
+ if (!dev_desc->block_read)
+ return -1;
+
+ /* check if we have a MBR (on floppies we have only a PBR) */
+ if (dev_desc->block_read(dev_desc->dev, 0, 1, (ulong *) buffer) != 1) {
+ printf("** Can't read from device %d **\n", dev_desc->dev);
+ return -1;
+ }
+ if (buffer[DOS_PART_MAGIC_OFFSET] != 0x55 ||
+ buffer[DOS_PART_MAGIC_OFFSET + 1] != 0xaa) {
+ /* no signature found */
+ return -1;
+ }
+
+ /* First we assume there is a MBR */
+ if (!get_partition_info(dev_desc, part_no, &info)) {
+ part_offset = info.start;
+ cur_part = part_no;
+ part_size = info.size;
+ } else if ((strncmp((char *)&buffer[DOS_FS_TYPE_OFFSET],
+ "FAT", 3) == 0) || (strncmp((char *)&buffer
+ [DOS_FS32_TYPE_OFFSET],
+ "FAT32", 5) == 0)) {
+ /* ok, we assume we are on a PBR only */
+ cur_part = 1;
+ part_offset = 0;
+ } else {
+ printf("** Partition %d not valid on device %d **\n",
+ part_no, dev_desc->dev);
+ return -1;
+ }
+
+ return 0;
+}
+
int do_ext4_load(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char *filename = NULL;
@@ -241,6 +283,94 @@ int do_ext4_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
return 0;
}
+int do_ext4_write(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+ char *filename = "/";
+ int part_length;
+ unsigned long part = 1;
+ int dev = 0;
+ char *ep;
+ unsigned long ram_address;
+ unsigned long file_size;
+ disk_partition_t info;
+ struct ext_filesystem *fs;
+
+ if (argc < 6)
+ return cmd_usage(cmdtp);
+
+ dev = (int)simple_strtoul(argv[2], &ep, 16);
+ ext4_dev_desc = get_dev(argv[1], dev);
+ if (ext4_dev_desc == NULL) {
+ printf("Block device %s %d not"
+ "supported\n", argv[1], dev);
+ return 1;
+ }
+ if (init_fs(ext4_dev_desc))
+ return 1;
+
+ fs = get_fs();
+ if (*ep) {
+ if (*ep != ':') {
+ puts("Invalid boot device, use `dev[:part]'\n");
+ goto fail;
+ }
+ (int)strict_strtoul(++ep, 16, &part);
+ }
+
+ /*get the filename */
+ filename = argv[3];
+
+ /*get the address in hexadecimal format (string to int) */
+ strict_strtoul(argv[4], 16, &ram_address);
+
+ /*get the filesize in base 10 format */
+ strict_strtoul(argv[5], 10, &file_size);
+
+ /*set the device as block device */
+ part_length = ext2fs_set_blk_dev(fs->dev_desc, part);
+ if (part_length == 0) {
+ printf("Bad partition - %s %d:%lu\n", argv[1], dev, part);
+ goto fail;
+ }
+
+ /*register the device and partition */
+ if (ext4_register_device(fs->dev_desc, part) != 0) {
+ printf("Unable to use %s %d:%lu for fattable\n",
+ argv[1], dev, part);
+ goto fail;
+ }
+
+ /*get the partition information */
+ if (!get_partition_info(fs->dev_desc, part, &info)) {
+ total_sector = (info.size * info.blksz) / SECTOR_SIZE;
+ fs->total_sect = total_sector;
+ } else {
+ printf("error : get partition info\n");
+ goto fail;
+ }
+
+ /*mount the filesystem */
+ if (!ext4fs_mount(part_length)) {
+ printf("Bad ext4 partition %s %d:%lu\n", argv[1], dev, part);
+ goto fail;
+ }
+
+ /*start write */
+ if (ext4fs_write(filename, (unsigned char *)ram_address, file_size)) {
+ printf("** Error ext4fs_write() **\n");
+ goto fail;
+ }
+
+ ext4fs_close();
+ deinit_fs(fs->dev_desc);
+ return 0;
+
+fail:
+ ext4fs_close();
+ deinit_fs(fs->dev_desc);
+ return 1;
+}
+
U_BOOT_CMD(ext4ls, 4, 1, do_ext4_ls,
"list files in a directory (default /)",
"<interface> <dev[:part]> [directory]\n"
@@ -251,3 +381,8 @@ U_BOOT_CMD(ext4load, 6, 0, do_ext4_load,
"<interface> <dev[:part]> [addr] [filename] [bytes]\n"
" - load binary file 'filename' from 'dev' on 'interface'\n"
" to address 'addr' from ext2 filesystem");
+U_BOOT_CMD
+ (ext4write, 6, 1, do_ext4_write,
+ "create a file in the root directory",
+ "<interface> <dev[:part]> [Absolute filename path] [Address] [sizebytes]\n"
+ " - create a file in / directory");
diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile
index 850f821..1e7e7a8 100644
--- a/fs/ext4/Makefile
+++ b/fs/ext4/Makefile
@@ -30,7 +30,7 @@ include $(TOPDIR)/config.mk
LIB = $(obj)libext4fs.o
AOBJS =
-COBJS-$(CONFIG_CMD_EXT4) := ext4fs.o ext4_common.o
+COBJS-$(CONFIG_CMD_EXT4) := ext4fs.o ext4_common.o ext4_journal.o crc16.o
SRCS := $(AOBJS:.o=.S) $(COBJS-y:.o=.c)
OBJS := $(addprefix $(obj),$(AOBJS) $(COBJS-y))
diff --git a/fs/ext4/crc16.c b/fs/ext4/crc16.c
new file mode 100644
index 0000000..3afb34d
--- /dev/null
+++ b/fs/ext4/crc16.c
@@ -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;
+}
diff --git a/fs/ext4/crc16.h b/fs/ext4/crc16.h
new file mode 100644
index 0000000..5fd113a
--- /dev/null
+++ b/fs/ext4/crc16.h
@@ -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(a)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
diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c
index 6f9351c..29b578d 100644
--- a/fs/ext4/ext4_common.c
+++ b/fs/ext4/ext4_common.c
@@ -22,7 +22,13 @@
/*
* ext4load - based on code from GRUB2 fs/ext2.c
-*/
+ *
+ * ext4write - based on existing ext2 support in UBOOT and ext4
+ * implementation in Linux Kernel
+ * Journaling feature of ext4 has been referred from JBD2
+ * (Journaling Block device 2) implementation in Linux Kernel
+ */
+
#include <common.h>
#include <ext_common.h>
#include <ext4fs.h>
@@ -30,7 +36,8 @@
#include <asm/byteorder.h>
#include <linux/stat.h>
#include <linux/time.h>
-#include "ext4_common.h"
+#include "crc16.h"
+#include "ext4_journal.h"
struct ext2_data *ext4fs_root;
struct ext2fs_node *ext4fs_file;
@@ -65,6 +72,834 @@ void *xzalloc(size_t size)
return ptr;
}
+uint32_t ext4fs_div_roundup(uint32_t size, uint32_t n)
+{
+ uint32_t res = size / n;
+ if (res * n != size)
+ res++;
+ return res;
+}
+
+/* To convert big endian journal superblock entries to little endian */
+unsigned int be_le(unsigned int num)
+{
+ unsigned int swapped;
+ swapped = (((num >> 24) & 0xff) |
+ ((num << 8) & 0xff0000) |
+ ((num >> 8) & 0xff00) | ((num << 24) & 0xff000000));
+ return swapped;
+}
+
+/* 4-byte number*/
+unsigned int le_be(unsigned int num)
+{
+ return ((num & 0xff) << 24) + ((num & 0xff00) << 8)
+ + ((num & 0xff0000) >> 8) + ((num >> 24) & 0xff);
+}
+
+void put_ext4(uint64_t off, void *buf, uint32_t size)
+{
+ uint64_t startblock, remainder;
+ short sector_size = 512;
+ unsigned char *temp_ptr = NULL;
+ char sec_buf[SECTOR_SIZE];
+ struct ext_filesystem *fs = get_fs();
+
+ startblock = off / (uint64_t) sector_size;
+ startblock += part_offset;
+ remainder = off % (uint64_t) sector_size;
+ remainder &= SECTOR_SIZE - 1;
+
+ if (fs->dev_desc == NULL)
+ return;
+
+ if ((startblock + (size / SECTOR_SIZE)) >
+ (part_offset + fs->total_sect)) {
+ printf("part_offset is %lu\n", part_offset);
+ printf("total_sector is %llu\n", fs->total_sect);
+ printf("error: overflow occurs\n");
+ return;
+ }
+
+ if (remainder) {
+ if (fs->dev_desc->block_read) {
+ fs->dev_desc->block_read(fs->dev_desc->dev,
+ startblock, 1,
+ (unsigned char *)sec_buf);
+ temp_ptr = (unsigned char *)sec_buf;
+ memcpy((temp_ptr + remainder),
+ (unsigned char *)buf, size);
+ fs->dev_desc->block_write(fs->dev_desc->dev,
+ startblock, 1,
+ (unsigned char *)sec_buf);
+ }
+ } else {
+ if (size / SECTOR_SIZE != 0) {
+ fs->dev_desc->block_write(fs->dev_desc->dev,
+ startblock,
+ size / SECTOR_SIZE,
+ (unsigned long *)buf);
+ } else {
+ fs->dev_desc->block_read(fs->dev_desc->dev,
+ startblock, 1,
+ (unsigned char *)sec_buf);
+ temp_ptr = (unsigned char *)sec_buf;
+ memcpy(temp_ptr, buf, size);
+ fs->dev_desc->block_write(fs->dev_desc->dev,
+ startblock, 1,
+ (unsigned long *)sec_buf);
+ }
+ }
+ return;
+}
+
+static int _get_new_inode_no(unsigned char *buffer)
+{
+ struct ext_filesystem *fs = get_fs();
+ unsigned char input;
+ int operand, status, count = 1, j = 0;
+
+ /*get the blocksize of the filesystem */
+ unsigned char *ptr = buffer;
+ while (*ptr == 255) {
+ ptr++;
+ count += 8;
+ if (count > (uint32_t) ext4fs_root->sblock.inodes_per_group)
+ return -1;
+ }
+
+ for (j = 0; j < fs->blksz; j++) {
+ input = *ptr;
+ int i = 0;
+ while (i <= 7) {
+ operand = 1 << i;
+ status = input & operand;
+ if (status) {
+ i++;
+ count++;
+ } else {
+ *ptr |= operand;
+ return count;
+ }
+ }
+ ptr = ptr + 1;
+ }
+ return -1;
+}
+
+static int _get_new_blk_no(unsigned char *buffer)
+{
+ unsigned char input;
+ int operand, status, count = 0, j = 0;
+ unsigned char *ptr = buffer;
+ struct ext_filesystem *fs = get_fs();
+
+ if (fs->blksz != 1024)
+ count = 0;
+ else
+ count = 1;
+
+ while (*ptr == 255) {
+ ptr++;
+ count += 8;
+ if (count == (fs->blksz * 8))
+ return -1;
+ }
+
+ for (j = 0; j < fs->blksz; j++) {
+ input = *ptr;
+ int i = 0;
+ while (i <= 7) {
+ operand = 1 << i;
+ status = input & operand;
+ if (status) {
+ i++;
+ count++;
+ } else {
+ *ptr |= operand;
+ return count;
+ }
+ }
+ ptr = ptr + 1;
+ }
+ return -1;
+}
+
+int set_block_bmap(long int blockno, unsigned char *buffer, int index)
+{
+ int i, remainder, status;
+ unsigned char *ptr = buffer;
+ unsigned char operand;
+ i = blockno / 8;
+ remainder = blockno % 8;
+ int blocksize = EXT2_BLOCK_SIZE(ext4fs_root);
+
+ i = i - (index * blocksize);
+ if (blocksize != 1024) {
+ ptr = ptr + i;
+ operand = 1 << remainder;
+ status = *ptr & operand;
+ if (status)
+ return -1;
+ else {
+ *ptr = *ptr | operand;
+ return 0;
+ }
+ } else {
+ if (remainder == 0) {
+ ptr = ptr + i - 1;
+ operand = (1 << 7);
+ } else {
+ ptr = ptr + i;
+ operand = (1 << (remainder - 1));
+ }
+ status = *ptr & operand;
+ if (status)
+ return -1;
+ else {
+ *ptr = *ptr | operand;
+ return 0;
+ }
+ }
+}
+
+void reset_block_bmap(long int blockno, unsigned char *buffer, int index)
+{
+ int i, remainder, status;
+ unsigned char *ptr = buffer;
+ unsigned char operand;
+ i = blockno / 8;
+ remainder = blockno % 8;
+ int blocksize = EXT2_BLOCK_SIZE(ext4fs_root);
+
+ i = i - (index * blocksize);
+ if (blocksize != 1024) {
+ ptr = ptr + i;
+ operand = (1 << remainder);
+ status = *ptr & operand;
+ if (status)
+ *ptr = *ptr & ~(operand);
+ } else {
+ if (remainder == 0) {
+ ptr = ptr + i - 1;
+ operand = (1 << 7);
+ } else {
+ ptr = ptr + i;
+ operand = (1 << (remainder - 1));
+ }
+ status = *ptr & operand;
+ if (status)
+ *ptr = *ptr & ~(operand);
+ }
+ return;
+}
+
+int set_inode_bmap(int inode_no, unsigned char *buffer, int index)
+{
+ int i, remainder, status;
+ unsigned char *ptr = buffer;
+ unsigned char operand;
+
+ inode_no -= (index * (uint32_t) ext4fs_root->sblock.inodes_per_group);
+ i = inode_no / 8;
+ remainder = inode_no % 8;
+ if (remainder == 0) {
+ ptr = ptr + i - 1;
+ operand = (1 << 7);
+ } else {
+ ptr = ptr + i;
+ operand = (1 << (remainder - 1));
+ }
+ status = *ptr & operand;
+ if (status)
+ return -1;
+ else {
+ *ptr = *ptr | operand;
+ return 0;
+ }
+}
+
+void reset_inode_bmap(int inode_no, unsigned char *buffer, int index)
+{
+ int i, remainder, status;
+ unsigned char *ptr = buffer;
+ unsigned char operand;
+
+ inode_no -= (index * (uint32_t) ext4fs_root->sblock.inodes_per_group);
+ i = inode_no / 8;
+ remainder = inode_no % 8;
+ if (remainder == 0) {
+ ptr = ptr + i - 1;
+ operand = (1 << 7);
+ } else {
+ ptr = ptr + i;
+ operand = (1 << (remainder - 1));
+ }
+ status = *ptr & operand;
+ if (status)
+ *ptr = *ptr & ~(operand);
+ return;
+}
+
+int ext4fs_checksum_update(unsigned int i)
+{
+ struct ext2_block_group *desc;
+ struct ext_filesystem *fs = get_fs();
+ __u16 crc = 0;
+
+ desc = (struct ext2_block_group *)&fs->gd[i];
+ if (fs->sb->feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
+ int offset = offsetof(struct ext2_block_group, bg_checksum);
+
+ crc = ext2fs_crc16(~0, fs->sb->unique_id,
+ sizeof(fs->sb->unique_id));
+ crc = ext2fs_crc16(crc, &i, sizeof(i));
+ crc = ext2fs_crc16(crc, desc, offset);
+ offset += sizeof(desc->bg_checksum); /* skip checksum */
+ assert(offset == sizeof(*desc));
+ }
+ return crc;
+}
+
+static int check_void_in_dentry(struct ext2_dirent *dir, char *filename)
+{
+ int dentry_length = 0;
+ short padding_factor = 0;
+ int sizeof_void_space = 0;
+ int new_entry_byte_reqd = 0;
+
+ if (dir->namelen % 4 != 0)
+ padding_factor = 4 - (dir->namelen % 4);
+
+ dentry_length = sizeof(struct ext2_dirent) +
+ dir->namelen + padding_factor;
+ sizeof_void_space = dir->direntlen - dentry_length;
+ if (sizeof_void_space == 0) {
+ return 0;
+ } else {
+ padding_factor = 0;
+ if (strlen(filename) % 4 != 0)
+ padding_factor = 4 - (strlen(filename) % 4);
+
+ new_entry_byte_reqd = strlen(filename) +
+ sizeof(struct ext2_dirent) + padding_factor;
+ if (sizeof_void_space >= new_entry_byte_reqd) {
+ dir->direntlen = dentry_length;
+ return sizeof_void_space;
+ } else
+ return 0;
+ }
+}
+
+void update_parent_dentry(char *filename, int *p_ino, int file_type)
+{
+ unsigned int *zero_buffer = NULL;
+ char *root_first_block_buffer = NULL;
+ struct ext_filesystem *fs = get_fs();
+ int direct_blk_idx;
+ long int root_blknr;
+ long int first_block_no_of_root = 0;
+ long int previous_blknr = -1;
+ int totalbytes = 0;
+ short int padding_factor = 0;
+ unsigned int new_entry_byte_reqd;
+ unsigned int last_entry_dirlen;
+ int sizeof_void_space = 0;
+ int templength = 0, inodeno, status;
+ /*directory entry */
+ struct ext2_dirent *dir;
+ char *ptr = NULL;
+ char *temp_dir = NULL;
+
+ /*##START: Update the root directory entry block of root inode ### */
+ /*since we are populating this file under root
+ *directory take the root inode and its first block
+ *currently we are looking only in first block of root
+ *inode*/
+
+ zero_buffer = xzalloc(fs->blksz);
+ if (!zero_buffer)
+ return;
+ root_first_block_buffer = (char *)xzalloc(fs->blksz);
+ if (!root_first_block_buffer)
+ return;
+RESTART:
+
+ /*read the block no allocated to a file */
+ for (direct_blk_idx = 0; direct_blk_idx < INDIRECT_BLOCKS;
+ direct_blk_idx++) {
+ root_blknr = read_allocated_block(g_parent_inode,
+ direct_blk_idx);
+ if (root_blknr == 0) {
+ first_block_no_of_root = previous_blknr;
+ break;
+ }
+ previous_blknr = root_blknr;
+ }
+
+ status = ext2fs_devread(first_block_no_of_root
+ * fs->sect_perblk,
+ 0, fs->blksz, root_first_block_buffer);
+ if (status == 0)
+ goto fail;
+ else {
+ if (log_journal(root_first_block_buffer,
+ first_block_no_of_root))
+ goto fail;
+ dir = (struct ext2_dirent *)root_first_block_buffer;
+ ptr = (char *)dir;
+ totalbytes = 0;
+ while (dir->direntlen > 0) {
+ /* blocksize-totalbytes because last directory length
+ * i.e. dir->direntlen is free availble space in the
+ * block that means it is a last entry of directory
+ * entry
+ */
+
+ /* traversing the each directory entry */
+ if (fs->blksz - totalbytes == dir->direntlen) {
+ if (strlen(filename) % 4 != 0)
+ padding_factor = 4 -
+ (strlen(filename) % 4);
+
+ new_entry_byte_reqd = strlen(filename) +
+ sizeof(struct ext2_dirent) + padding_factor;
+ padding_factor = 0;
+ /* update last directory entry length to its
+ * length because we are creating new directory
+ * entry */
+ if (dir->namelen % 4 != 0)
+ padding_factor = 4 - (dir->namelen % 4);
+
+ last_entry_dirlen = dir->namelen +
+ sizeof(struct ext2_dirent) + padding_factor;
+ if ((fs->blksz - totalbytes - last_entry_dirlen)
+ < new_entry_byte_reqd) {
+ printf("1st Block Full:"
+ "allocating new block\n");
+
+ if (direct_blk_idx ==
+ INDIRECT_BLOCKS - 1) {
+ printf("Directory capacity"
+ "exceeds the limit\n");
+ goto fail;
+ }
+ g_parent_inode->b.blocks.dir_blocks
+ [direct_blk_idx] = get_new_blk_no();
+ if (g_parent_inode->b.blocks.dir_blocks
+ [direct_blk_idx] == -1) {
+ printf("no block"
+ "left to assign\n");
+ goto fail;
+ }
+ put_ext4(((uint64_t)
+ (g_parent_inode->b.blocks.
+ dir_blocks[direct_blk_idx] *
+ fs->blksz)), zero_buffer,
+ fs->blksz);
+ g_parent_inode->size =
+ g_parent_inode->size + fs->blksz;
+ g_parent_inode->blockcnt =
+ g_parent_inode->blockcnt +
+ fs->sect_perblk;
+ if (put_metadata
+ (root_first_block_buffer,
+ first_block_no_of_root))
+ goto fail;
+ goto RESTART;
+ }
+ dir->direntlen = last_entry_dirlen;
+ break;
+ }
+
+ templength = dir->direntlen;
+ totalbytes = totalbytes + templength;
+ sizeof_void_space = check_void_in_dentry(dir, filename);
+ if (sizeof_void_space)
+ break;
+
+ dir = (struct ext2_dirent *)((char *)dir + templength);
+ ptr = (char *)dir;
+ }
+
+ /*make a pointer ready for creating next directory entry */
+ templength = dir->direntlen;
+ totalbytes = totalbytes + templength;
+ dir = (struct ext2_dirent *)((char *)dir + templength);
+ ptr = (char *)dir;
+
+ /*get the next available inode number */
+ inodeno = get_new_inode_no();
+ if (inodeno == -1) {
+ printf("no inode left to assign\n");
+ goto fail;
+ }
+ dir->inode = inodeno;
+ if (sizeof_void_space)
+ dir->direntlen = sizeof_void_space;
+ else
+ dir->direntlen = fs->blksz - totalbytes;
+ dir->namelen = strlen(filename);
+ dir->filetype = FILETYPE_REG; /*regular file */
+ temp_dir = (char *)dir;
+ temp_dir = temp_dir + sizeof(struct ext2_dirent);
+ memcpy(temp_dir, filename, strlen(filename));
+ }
+ *p_ino = inodeno;
+
+ /*update or write the 1st block of root inode */
+ if (put_metadata(root_first_block_buffer, first_block_no_of_root))
+ goto fail;
+
+fail:
+ if (zero_buffer)
+ free(zero_buffer);
+ if (root_first_block_buffer)
+ free(root_first_block_buffer);
+
+ /*END: Update the root directory entry block of root inode */
+}
+
+static int search_dir(struct ext2_inode *parent_inode, char *dirname)
+{
+ unsigned char *block_buffer;
+ struct ext_filesystem *fs = get_fs();
+ struct ext2_dirent *dir = NULL;
+ struct ext2_dirent *previous_dir = NULL;
+ int status, inodeno, totalbytes, templength, direct_blk_idx;
+ int found = 0;
+ char *ptr;
+ long int blknr;
+
+ /*get the first block of root */
+ /*read the block no allocated to a file */
+ for (direct_blk_idx = 0; direct_blk_idx < INDIRECT_BLOCKS;
+ direct_blk_idx++) {
+ blknr = read_allocated_block(parent_inode, direct_blk_idx);
+ if (blknr == 0)
+ goto fail;
+
+ /*read the blocks of parenet inode */
+ block_buffer = xzalloc(fs->blksz);
+ if (!block_buffer)
+ goto fail;
+
+ status = ext2fs_devread(blknr * fs->sect_perblk,
+ 0, fs->blksz, (char *)block_buffer);
+ if (status == 0)
+ goto fail;
+ else {
+ dir = (struct ext2_dirent *)block_buffer;
+ ptr = (char *)dir;
+ totalbytes = 0;
+ while (dir->direntlen >= 0) {
+ /*blocksize-totalbytes because last directory
+ *length i.e.,*dir->direntlen is free availble
+ *space in the block that means
+ *it is a last entry of directory entry
+ */
+ if (strlen(dirname) == dir->namelen) {
+ if (strncmp(dirname, ptr +
+ sizeof(struct ext2_dirent),
+ dir->namelen) == 0) {
+ previous_dir->direntlen +=
+ dir->direntlen;
+ inodeno = dir->inode;
+ dir->inode = 0;
+ found = 1;
+ break;
+ }
+ }
+
+ if (fs->blksz - totalbytes == dir->direntlen)
+ break;
+
+ /*traversing the each directory entry */
+ templength = dir->direntlen;
+ totalbytes = totalbytes + templength;
+ previous_dir = dir;
+ dir = (struct ext2_dirent *)((char *)dir
+ + templength);
+ ptr = (char *)dir;
+ }
+ }
+
+ if (found == 1) {
+ if (block_buffer) {
+ free(block_buffer);
+ block_buffer = NULL;
+ }
+ return inodeno;
+ }
+
+ if (block_buffer) {
+ free(block_buffer);
+ block_buffer = NULL;
+ }
+ }
+
+fail:
+ if (block_buffer) {
+ free(block_buffer);
+ block_buffer = NULL;
+ }
+ return -1;
+}
+
+static int find_dir_depth(char *dirname)
+{
+ char *token = strtok(dirname, "/");
+ int count = 0;
+ while (token != NULL) {
+ token = strtok(NULL, "/");
+ count++;
+ }
+ return count + 1 + 1;
+ /*
+ *for example for string /home/temp
+ *depth=home(1)+temp(1)+1 extra for NULL;
+ *so count is 4;
+ */
+}
+
+static int parse_path(char **arr, char *dirname)
+{
+ char *token = strtok(dirname, "/");
+ int i = 0;
+
+ /*add root */
+ arr[i] = xzalloc(strlen("/") + 1);
+ if (!arr[i])
+ return -1;
+
+ arr[i++] = "/";
+
+ /*add each path entry after root */
+ while (token != NULL) {
+ arr[i] = xzalloc(strlen(token) + 1);
+ if (!arr[i])
+ return -1;
+ memcpy(arr[i++], token, strlen(token));
+ token = strtok(NULL, "/");
+ }
+
+ arr[i] = NULL;
+ /*success */
+ return 0;
+}
+
+int iget(int inode_no, struct ext2_inode *inode)
+{
+ if (ext4fs_read_inode(ext4fs_root, inode_no, inode) == 0)
+ return -1;
+ else
+ return 0;
+}
+
+/*
+* Function:get_parent_inode_num
+* Return Value: inode Number of the parent directory of file/Directory to be
+* created
+* dirname : Input parmater, input path name of the file/directory to be created
+* dname : Output parameter, to be filled with the name of the directory
+* extracted from dirname
+*/
+int get_parent_inode_num(char *dirname, char *dname, int flags)
+{
+ char **ptr = NULL;
+ int i, depth = 0;
+ char *depth_dirname = NULL;
+ char *parse_dirname = NULL;
+ struct ext2_inode *parent_inode = NULL;
+ struct ext2_inode *first_inode = NULL;
+ struct ext2_inode temp_inode;
+ int matched_inode_no;
+ int result_inode_no = -1;
+
+ if (*dirname != '/') {
+ printf("Please supply Absolute path\n");
+ return -1;
+ }
+
+ depth_dirname = (char *)xzalloc(strlen(dirname) + 1);
+ if (!depth_dirname)
+ return -1;
+
+ memcpy(depth_dirname, dirname, strlen(dirname));
+ depth = find_dir_depth(depth_dirname);
+ parse_dirname = (char *)xzalloc(strlen(dirname) + 1);
+ if (!parse_dirname)
+ goto fail;
+ memcpy(parse_dirname, dirname, strlen(dirname));
+
+ ptr = (char **)xzalloc((depth) * sizeof(char *));
+ if (!ptr)
+ goto fail;
+ if (parse_path(ptr, parse_dirname))
+ goto fail;
+ parent_inode = (struct ext2_inode *)
+ xzalloc(sizeof(struct ext2_inode));
+ if (!parent_inode)
+ goto fail;
+ first_inode = (struct ext2_inode *)
+ xzalloc(sizeof(struct ext2_inode));
+ if (!first_inode)
+ goto fail;
+ memcpy(parent_inode, ext4fs_root->inode, sizeof(struct ext2_inode));
+ memcpy(first_inode, parent_inode, sizeof(struct ext2_inode));
+ if (flags & F_FILE)
+ result_inode_no = EXT2_ROOT_INO;
+ for (i = 1; i < depth; i++) {
+ matched_inode_no = search_dir(parent_inode, ptr[i]);
+ if (matched_inode_no == -1) {
+ if (ptr[i + 1] == NULL && i == 1) {
+ result_inode_no = EXT2_ROOT_INO;
+ goto END;
+ } else {
+ if (ptr[i + 1] == NULL)
+ break;
+ printf("Invalid path\n");
+ result_inode_no = -1;
+ goto fail;
+ }
+ } else {
+ if (ptr[i + 1] != NULL) {
+ memset(parent_inode, '\0',
+ sizeof(struct ext2_inode));
+ if (iget(matched_inode_no, parent_inode)) {
+ result_inode_no = -1;
+ goto fail;
+ }
+ result_inode_no = matched_inode_no;
+ } else
+ break;
+ }
+ }
+
+END:
+ if (i == 1)
+ matched_inode_no = search_dir(first_inode, ptr[i]);
+ else
+ matched_inode_no = search_dir(parent_inode, ptr[i]);
+
+ if (matched_inode_no != -1) {
+ iget(matched_inode_no, &temp_inode);
+ if (temp_inode.mode & S_IFDIR) {
+ printf("It is a Directory\n");
+ result_inode_no = -1;
+ goto fail;
+ }
+ }
+
+ if (strlen(ptr[i]) > 256) {
+ result_inode_no = -1;
+ goto fail;
+ }
+ memcpy(dname, ptr[i], strlen(ptr[i]));
+
+fail:
+ if (depth_dirname)
+ free(depth_dirname);
+ if (parse_dirname)
+ free(parse_dirname);
+ if (ptr)
+ free(ptr);
+ if (parent_inode)
+ free(parent_inode);
+ if (first_inode)
+ free(first_inode);
+
+ return result_inode_no;
+}
+
+static int check_filename(char *filename, unsigned int blknr)
+{
+ char *root_first_block_buffer, *root_first_block_addr;
+ unsigned int first_block_no_of_root;
+ struct ext_filesystem *fs = get_fs();
+ struct ext2_dirent *dir;
+ struct ext2_dirent *previous_dir = NULL;
+ int totalbytes = 0;
+ int templength = 0;
+ int status, inodeno;
+ int found = 0;
+ char *ptr;
+
+ first_block_no_of_root = blknr;
+ root_first_block_buffer = (char *)xzalloc(fs->blksz);
+ if (!root_first_block_buffer)
+ return -1;
+ root_first_block_addr = root_first_block_buffer;
+ status = ext2fs_devread(first_block_no_of_root *
+ fs->sect_perblk, 0,
+ fs->blksz, root_first_block_buffer);
+ if (status == 0) {
+ goto fail;
+ } else {
+ if (log_journal(root_first_block_buffer,
+ first_block_no_of_root))
+ goto fail;
+ dir = (struct ext2_dirent *)root_first_block_buffer;
+ ptr = (char *)dir;
+ totalbytes = 0;
+ while (dir->direntlen >= 0) {
+ if (strlen(filename) == dir->namelen) {
+ if (strncmp(filename,
+ ptr + sizeof(struct ext2_dirent),
+ dir->namelen) == 0) {
+ printf("file found deleting\n");
+ previous_dir->direntlen +=
+ dir->direntlen;
+ inodeno = dir->inode;
+ dir->inode = 0;
+ found = 1;
+ break;
+ }
+ }
+
+ if (fs->blksz - totalbytes == dir->direntlen)
+ break;
+
+ /*traversing the each directory entry */
+ templength = dir->direntlen;
+ totalbytes = totalbytes + templength;
+ previous_dir = dir;
+ dir = (struct ext2_dirent *)((char *)dir + templength);
+ ptr = (char *)dir;
+ }
+ }
+
+ if (found == 1) {
+ if (put_metadata(root_first_block_addr, first_block_no_of_root))
+ goto fail;
+ return inodeno;
+ }
+
+fail:
+ if (root_first_block_buffer)
+ free(root_first_block_buffer);
+ return -1;
+}
+
+int ext4fs_filename_check(char *filename)
+{
+ short direct_blk_idx = 0;
+ long int blknr = -1;
+ int inodeno = -1;
+
+ /*read the block no allocated to a file */
+ for (direct_blk_idx = 0; direct_blk_idx < INDIRECT_BLOCKS;
+ direct_blk_idx++) {
+ blknr = read_allocated_block(g_parent_inode, direct_blk_idx);
+ if (blknr == 0)
+ break;
+ inodeno = check_filename(filename, blknr);
+ if (inodeno != -1)
+ return inodeno;
+ }
+ return -1;
+}
+
static struct ext4_extent_header *ext4fs_find_leaf(struct ext2_data *data,
char *buf, struct ext4_extent_header *ext_block, uint32_t fileblock)
{
@@ -152,6 +987,553 @@ int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode)
return 1;
}
+long int get_new_blk_no(void)
+{
+ short i, status;
+ int remainder;
+ unsigned int bg_idx;
+ static int prev_bg_bitmap_index = -1;
+ struct ext_filesystem *fs = get_fs();
+ char *journal_buffer = (char *)xzalloc(fs->blksz);
+ char *zero_buffer = (char *)xzalloc(fs->blksz);
+ if (!journal_buffer || !zero_buffer)
+ goto fail;
+ struct ext2_block_group *gd = (struct ext2_block_group *)fs->gdtable;
+
+ if (fs->first_pass_bbmap == 0) {
+ for (i = 0; i < fs->no_blkgrp; i++) {
+ if (gd[i].free_blocks) {
+ if (gd[i].bg_flags & EXT4_BG_BLOCK_UNINIT) {
+ put_ext4(((uint64_t) (gd[i].block_id *
+ fs->blksz)),
+ zero_buffer, fs->blksz);
+ gd[i].bg_flags =
+ gd[i].
+ bg_flags & ~EXT4_BG_BLOCK_UNINIT;
+ memcpy(fs->blk_bmaps[i], zero_buffer,
+ fs->blksz);
+ }
+ fs->curr_blkno =
+ _get_new_blk_no(fs->blk_bmaps[i]);
+ if (fs->curr_blkno == -1) {
+ /*if block bitmap is completely fill */
+ continue;
+ }
+ fs->curr_blkno = fs->curr_blkno +
+ (i * fs->blksz * 8);
+ fs->first_pass_bbmap++;
+ gd[i].free_blocks--;
+ fs->sb->free_blocks--;
+ status = ext2fs_devread(gd[i].block_id *
+ fs->sect_perblk, 0,
+ fs->blksz,
+ journal_buffer);
+ if (status == 0)
+ goto fail;
+ if (log_journal(journal_buffer, gd[i].block_id))
+ goto fail;
+ goto success;
+ } else {
+ debug("no space left on block group %d\n", i);
+ }
+ }
+ goto fail;
+ } else {
+restart:
+ fs->curr_blkno++;
+ /*get the blockbitmap index respective to blockno */
+ if (fs->blksz != 1024) {
+ bg_idx = fs->curr_blkno /
+ (uint32_t) ext4fs_root->sblock.blocks_per_group;
+ } else {
+ bg_idx = fs->curr_blkno /
+ (uint32_t) ext4fs_root->sblock.blocks_per_group;
+ remainder = fs->curr_blkno %
+ (uint32_t) ext4fs_root->sblock.blocks_per_group;
+ if (!remainder)
+ bg_idx--;
+ }
+
+ if (bg_idx >= fs->no_blkgrp)
+ goto fail;
+
+ if (gd[bg_idx].free_blocks == 0) {
+ debug("block group %u is full. Skipping\n", bg_idx);
+ fs->curr_blkno = fs->curr_blkno +
+ ext4fs_root->sblock.blocks_per_group;
+ fs->curr_blkno--;
+ goto restart;
+ }
+
+ if (gd[bg_idx].bg_flags & EXT4_BG_BLOCK_UNINIT) {
+ memset(zero_buffer, '\0', fs->blksz);
+ put_ext4(((uint64_t) (gd[bg_idx].block_id * fs->blksz)),
+ zero_buffer, fs->blksz);
+ memcpy(fs->blk_bmaps[bg_idx], zero_buffer, fs->blksz);
+ gd[bg_idx].bg_flags = gd[bg_idx].bg_flags &
+ ~EXT4_BG_BLOCK_UNINIT;
+ }
+
+ if (set_block_bmap(fs->curr_blkno, fs->blk_bmaps[bg_idx],
+ bg_idx) != 0) {
+ debug("going for restart for the block no %ld %u\n",
+ fs->curr_blkno, bg_idx);
+ goto restart;
+ }
+
+ /*journal backup */
+ if (prev_bg_bitmap_index != bg_idx) {
+ memset(journal_buffer, '\0', fs->blksz);
+ status = ext2fs_devread(gd[bg_idx].block_id
+ * fs->sect_perblk,
+ 0, fs->blksz, journal_buffer);
+ if (status == 0)
+ goto fail;
+ if (log_journal(journal_buffer, gd[bg_idx].block_id))
+ goto fail;
+
+ prev_bg_bitmap_index = bg_idx;
+ }
+ gd[bg_idx].free_blocks--;
+ fs->sb->free_blocks--;
+ goto success;
+ }
+success:
+ if (journal_buffer)
+ free(journal_buffer);
+ if (zero_buffer)
+ free(zero_buffer);
+ return fs->curr_blkno;
+fail:
+ if (journal_buffer)
+ free(journal_buffer);
+ if (zero_buffer)
+ free(zero_buffer);
+ return -1;
+}
+
+int get_new_inode_no(void)
+{
+ short i, status;
+ unsigned int ibmap_idx;
+ static int prev_inode_bitmap_index = -1;
+ struct ext_filesystem *fs = get_fs();
+ char *journal_buffer = (char *)xzalloc(fs->blksz);
+ char *zero_buffer = (char *)xzalloc(fs->blksz);
+ if (!journal_buffer || !zero_buffer)
+ goto fail;
+ struct ext2_block_group *gd = (struct ext2_block_group *)fs->gdtable;
+
+ if (fs->first_pass_ibmap == 0) {
+ for (i = 0; i < fs->no_blkgrp; i++) {
+ if (gd[i].free_inodes) {
+ if (gd[i].bg_flags & EXT4_BG_INODE_UNINIT) {
+ put_ext4(((uint64_t)
+ (gd[i].inode_id * fs->blksz)),
+ zero_buffer, fs->blksz);
+ gd[i].bg_flags = gd[i].bg_flags &
+ ~EXT4_BG_INODE_UNINIT;
+ memcpy(fs->inode_bmaps[i],
+ zero_buffer, fs->blksz);
+ }
+ fs->curr_inode_no =
+ _get_new_inode_no(fs->inode_bmaps[i]);
+ if (fs->curr_inode_no == -1) {
+ /*if block bitmap is completely fill */
+ continue;
+ }
+ fs->curr_inode_no = fs->curr_inode_no +
+ (i * ext4fs_root->sblock.inodes_per_group);
+ fs->first_pass_ibmap++;
+ gd[i].free_inodes--;
+ gd[i].bg_itable_unused--;
+ fs->sb->free_inodes--;
+ status = ext2fs_devread(gd[i].inode_id *
+ fs->sect_perblk, 0,
+ fs->blksz,
+ journal_buffer);
+ if (status == 0)
+ goto fail;
+ if (log_journal(journal_buffer, gd[i].inode_id))
+ goto fail;
+ goto success;
+ } else
+ debug("no inode left on block group %d\n", i);
+ }
+ goto fail;
+ } else {
+restart:
+ fs->curr_inode_no++;
+ /*get the blockbitmap index respective to blockno */
+ ibmap_idx = fs->curr_inode_no /
+ (uint32_t) ext4fs_root->sblock.inodes_per_group;
+ if (gd[ibmap_idx].bg_flags & EXT4_BG_INODE_UNINIT) {
+ memset(zero_buffer, '\0', fs->blksz);
+ put_ext4(((uint64_t) (gd[ibmap_idx].inode_id *
+ fs->blksz)), zero_buffer,
+ fs->blksz);
+ gd[ibmap_idx].bg_flags =
+ gd[ibmap_idx].bg_flags & ~EXT4_BG_INODE_UNINIT;
+ memcpy(fs->inode_bmaps[ibmap_idx], zero_buffer,
+ fs->blksz);
+ }
+
+ if (set_inode_bmap(fs->curr_inode_no,
+ fs->inode_bmaps[ibmap_idx],
+ ibmap_idx) != 0) {
+ debug("going for restart for the block no %d %u\n",
+ fs->curr_inode_no, ibmap_idx);
+ goto restart;
+ }
+
+ /*journal backup */
+ if (prev_inode_bitmap_index != ibmap_idx) {
+ memset(journal_buffer, '\0', fs->blksz);
+ status = ext2fs_devread(gd[ibmap_idx].inode_id
+ * fs->sect_perblk,
+ 0, fs->blksz, journal_buffer);
+ if (status == 0)
+ goto fail;
+ if (log_journal(journal_buffer, gd[ibmap_idx].inode_id))
+ goto fail;
+ prev_inode_bitmap_index = ibmap_idx;
+ }
+
+ gd[ibmap_idx].free_inodes--;
+ gd[ibmap_idx].bg_itable_unused--;
+ fs->sb->free_inodes--;
+ goto success;
+ }
+
+success:
+ if (journal_buffer)
+ free(journal_buffer);
+ if (zero_buffer)
+ free(zero_buffer);
+ return fs->curr_inode_no;
+
+fail:
+ if (journal_buffer)
+ free(journal_buffer);
+ if (zero_buffer)
+ free(zero_buffer);
+ return -1;
+
+}
+
+/*allocation of single indirect blocks*/
+static void alloc_single_indirect_block(struct ext2_inode *file_inode,
+ unsigned int *total_remaining_blocks,
+ unsigned int *no_blks_reqd)
+{
+ short i, status;
+ long int actual_block_no;
+ /*single indirect */
+ unsigned int *SI_buffer = NULL;
+ long int SI_blockno;
+ unsigned int *SI_start_addr = NULL;
+ struct ext_filesystem *fs = get_fs();
+
+ if (*total_remaining_blocks != 0) {
+ SI_buffer = xzalloc(fs->blksz);
+ if (!SI_buffer)
+ return;
+ SI_start_addr = SI_buffer;
+ SI_blockno = get_new_blk_no();
+ if (SI_blockno == -1) {
+ printf("no block left to assign\n");
+ goto fail;
+ }
+ (*no_blks_reqd)++;
+ debug("SIPB %ld: %u\n", SI_blockno, *total_remaining_blocks);
+
+ status = ext2fs_devread(SI_blockno * fs->sect_perblk,
+ 0, fs->blksz, (char *)SI_buffer);
+ memset(SI_buffer, '\0', fs->blksz);
+ if (status == 0)
+ goto fail;
+
+ for (i = 0; i < (fs->blksz / sizeof(int)); i++) {
+ actual_block_no = get_new_blk_no();
+ if (actual_block_no == -1) {
+ printf("no block left to assign\n");
+ goto fail;
+ }
+ *SI_buffer = actual_block_no;
+ debug("SIAB %u: %u\n", *SI_buffer,
+ *total_remaining_blocks);
+
+ SI_buffer++;
+ (*total_remaining_blocks)--;
+ if (*total_remaining_blocks == 0)
+ break;
+ }
+
+ /*write the block to disk */
+ put_ext4(((uint64_t) (SI_blockno * fs->blksz)),
+ SI_start_addr, fs->blksz);
+ file_inode->b.blocks.indir_block = SI_blockno;
+ }
+fail:
+ if (SI_start_addr)
+ free(SI_start_addr);
+ return;
+}
+
+/*allocation of double indirect blocks*/
+static void alloc_double_indirect_block(struct ext2_inode *file_inode,
+ unsigned int *total_remaining_blocks,
+ unsigned int *no_blks_reqd)
+{
+ short i, j, status;
+ long int actual_block_no;
+ /*double indirect */
+ long int DI_blockno_parent, DI_blockno_child;
+ unsigned int *DI_parent_buffer = NULL;
+ unsigned int *DI_child_buff = NULL;
+ unsigned int *DI_block_start_addr = NULL;
+ unsigned int *DI_child_buff_start = NULL;
+ struct ext_filesystem *fs = get_fs();
+
+ if (*total_remaining_blocks != 0) {
+ /*double indirect parent block connecting to inode */
+ DI_blockno_parent = get_new_blk_no();
+ if (DI_blockno_parent == -1) {
+ printf("no block left to assign\n");
+ goto fail;
+ }
+ DI_parent_buffer = xzalloc(fs->blksz);
+ if (!DI_parent_buffer)
+ goto fail;
+
+ DI_block_start_addr = DI_parent_buffer;
+ (*no_blks_reqd)++;
+ debug("DIPB %ld: %u\n", DI_blockno_parent,
+ *total_remaining_blocks);
+
+ status = ext2fs_devread(DI_blockno_parent *
+ fs->sect_perblk, 0,
+ fs->blksz, (char *)DI_parent_buffer);
+ memset(DI_parent_buffer, '\0', fs->blksz);
+
+ /*START: for each double indirect parent
+ *block create one more block*/
+ for (i = 0; i < (fs->blksz / sizeof(int)); i++) {
+ DI_blockno_child = get_new_blk_no();
+ if (DI_blockno_child == -1) {
+ printf("no block left to assign\n");
+ goto fail;
+ }
+ DI_child_buff = xzalloc(fs->blksz);
+ if (!DI_child_buff)
+ goto fail;
+
+ DI_child_buff_start = DI_child_buff;
+ *DI_parent_buffer = DI_blockno_child;
+ DI_parent_buffer++;
+ (*no_blks_reqd)++;
+ debug("DICB %ld: %u\n", DI_blockno_child,
+ *total_remaining_blocks);
+
+ status = ext2fs_devread(DI_blockno_child *
+ fs->sect_perblk, 0,
+ fs->blksz,
+ (char *)DI_child_buff);
+ memset(DI_child_buff, '\0', fs->blksz);
+ /*END: for each double indirect parent block block */
+ /*filling of actual datablocks for each child */
+ for (j = 0; j < (fs->blksz / sizeof(int)); j++) {
+ actual_block_no = get_new_blk_no();
+ if (actual_block_no == -1) {
+ printf("no block left to assign\n");
+ goto fail;
+ }
+ *DI_child_buff = actual_block_no;
+ debug("DIAB %ld: %u\n", actual_block_no,
+ *total_remaining_blocks);
+
+ DI_child_buff++;
+ (*total_remaining_blocks)--;
+ if (*total_remaining_blocks == 0)
+ break;
+ }
+ /*write the block table */
+ put_ext4(((uint64_t) (DI_blockno_child * fs->blksz)),
+ DI_child_buff_start, fs->blksz);
+ if (DI_child_buff_start)
+ free(DI_child_buff_start);
+
+ if (*total_remaining_blocks == 0)
+ break;
+ }
+ put_ext4(((uint64_t) (DI_blockno_parent * fs->blksz)),
+ DI_block_start_addr, fs->blksz);
+ file_inode->b.blocks.double_indir_block = DI_blockno_parent;
+ }
+fail:
+ if (DI_block_start_addr)
+ free(DI_block_start_addr);
+ return;
+}
+
+/*allocation of triple indirect blocks*/
+static void alloc_triple_indirect_block(struct ext2_inode *file_inode,
+ unsigned int *total_remaining_blocks,
+ unsigned int *no_blks_reqd)
+{
+ short i, j, k;
+ long int actual_block_no;
+ /*Triple Indirect */
+ long int TI_gp_blockno, TI_parent_blockno, TI_child_blockno;
+ unsigned int *TI_gp_buff = NULL;
+ unsigned int *TI_parent_buff = NULL;
+ unsigned int *TI_child_buff = NULL;
+ unsigned int *TI_gp_buff_start_addr = NULL;
+ unsigned int *TI_pbuff_start_addr = NULL;
+ unsigned int *TI_cbuff_start_addr = NULL;
+ struct ext_filesystem *fs = get_fs();
+ if (*total_remaining_blocks != 0) {
+ /*triple indirect grand parent block connecting to inode */
+ TI_gp_blockno = get_new_blk_no();
+ if (TI_gp_blockno == -1) {
+ printf("no block left to assign\n");
+ goto fail;
+ }
+ TI_gp_buff = xzalloc(fs->blksz);
+ if (!TI_gp_buff)
+ goto fail;
+
+ TI_gp_buff_start_addr = TI_gp_buff;
+ (*no_blks_reqd)++;
+ debug("TIGPB %ld: %u\n", TI_gp_blockno,
+ *total_remaining_blocks);
+
+ /* for each 4 byte grand parent entry create one more block */
+ for (i = 0; i < (fs->blksz / sizeof(int)); i++) {
+ TI_parent_blockno = get_new_blk_no();
+ if (TI_parent_blockno == -1) {
+ printf("no block left to assign\n");
+ goto fail;
+ }
+ TI_parent_buff = xzalloc(fs->blksz);
+ if (!TI_parent_buff)
+ goto fail;
+
+ TI_pbuff_start_addr = TI_parent_buff;
+ *TI_gp_buff = TI_parent_blockno;
+ TI_gp_buff++;
+ (*no_blks_reqd)++;
+ debug("TIPB %ld: %u\n", TI_parent_blockno,
+ *total_remaining_blocks);
+
+ /*for each 4 byte entry parent create one more block */
+ for (j = 0; j < (fs->blksz / sizeof(int)); j++) {
+ TI_child_blockno = get_new_blk_no();
+ if (TI_child_blockno == -1) {
+ printf("no block"
+ "left assign\n");
+ goto fail;
+ }
+ TI_child_buff = xzalloc(fs->blksz);
+ if (!TI_child_buff)
+ goto fail;
+
+ TI_cbuff_start_addr = TI_child_buff;
+ *TI_parent_buff = TI_child_blockno;
+ TI_parent_buff++;
+ (*no_blks_reqd)++;
+ debug("TICB %ld: %u\n", TI_parent_blockno,
+ *total_remaining_blocks);
+
+ /*filling of actual datablocks for each child */
+ for (k = 0; k < (fs->blksz / sizeof(int));
+ k++) {
+ actual_block_no = get_new_blk_no();
+ if (actual_block_no == -1) {
+ printf("no block"
+ "left to assign\n");
+ goto fail;
+ }
+ *TI_child_buff = actual_block_no;
+ debug("TIAB %ld: %u\n", actual_block_no,
+ *total_remaining_blocks);
+
+ TI_child_buff++;
+ (*total_remaining_blocks)--;
+ if (*total_remaining_blocks == 0)
+ break;
+ }
+ /*write the child block */
+ put_ext4(((uint64_t) (TI_child_blockno *
+ fs->blksz)),
+ TI_cbuff_start_addr, fs->blksz);
+ if (TI_cbuff_start_addr)
+ free(TI_cbuff_start_addr);
+
+ if (*total_remaining_blocks == 0)
+ break;
+ }
+ /*write the parent block */
+ put_ext4(((uint64_t) (TI_parent_blockno * fs->blksz)),
+ TI_pbuff_start_addr, fs->blksz);
+ if (TI_pbuff_start_addr)
+ free(TI_pbuff_start_addr);
+
+ if (*total_remaining_blocks == 0)
+ break;
+ }
+ /*write the grand parent block */
+ put_ext4(((uint64_t) (TI_gp_blockno * fs->blksz)),
+ TI_gp_buff_start_addr, fs->blksz);
+ file_inode->b.blocks.tripple_indir_block = TI_gp_blockno;
+ }
+fail:
+ if (TI_gp_buff_start_addr)
+ free(TI_gp_buff_start_addr);
+ return;
+}
+
+void allocate_blocks(struct ext2_inode *file_inode,
+ unsigned int total_remaining_blocks,
+ unsigned int *total_no_of_block)
+{
+ short i;
+ long int direct_blockno;
+ unsigned int no_blks_reqd = 0;
+
+ /*-------------START:Allocation of Blocks to Inode-------------*/
+ /*allocation of direct blocks */
+ for (i = 0; i < INDIRECT_BLOCKS; i++) {
+ direct_blockno = get_new_blk_no();
+ if (direct_blockno == -1) {
+ printf("no block left to assign\n");
+ return;
+ }
+ file_inode->b.blocks.dir_blocks[i] = direct_blockno;
+ debug("DB %ld: %u\n", direct_blockno, total_remaining_blocks);
+
+ total_remaining_blocks--;
+ if (total_remaining_blocks == 0)
+ break;
+ }
+
+ /*allocation of single indirect blocks */
+ alloc_single_indirect_block(file_inode, &total_remaining_blocks,
+ &no_blks_reqd);
+
+ /*allocation of double indirect blocks */
+ alloc_double_indirect_block(file_inode, &total_remaining_blocks,
+ &no_blks_reqd);
+
+ /*allocation of triple indirect blocks */
+ alloc_triple_indirect_block(file_inode, &total_remaining_blocks,
+ &no_blks_reqd);
+
+ /*-----------------END:Allocation of Blocks to Inode-------------- */
+ *total_no_of_block += no_blks_reqd;
+ return;
+}
+
long int read_allocated_block(struct ext2_inode *inode, int fileblock)
{
long int blknr;
diff --git a/fs/ext4/ext4_common.h b/fs/ext4/ext4_common.h
index 73f218d..a2a7e7a 100644
--- a/fs/ext4/ext4_common.h
+++ b/fs/ext4/ext4_common.h
@@ -41,4 +41,21 @@
extern unsigned long part_offset;
int ext4fs_read_inode(struct ext2_data *data, int ino,
struct ext2_inode *inode);
+uint32_t ext4fs_div_roundup(uint32_t size, uint32_t n);
+int ext4fs_checksum_update(unsigned int i);
+int get_parent_inode_num(char *dirname, char *dname, int flags);
+void update_parent_dentry(char *filename, int *p_ino, int file_type);
+long int get_new_blk_no(void);
+int get_new_inode_no(void);
+void reset_block_bmap(long int blockno, unsigned char *buffer, int index);
+int set_block_bmap(long int blockno, unsigned char *buffer, int index);
+int set_inode_bmap(int inode_no, unsigned char *buffer, int index);
+void reset_inode_bmap(int inode_no, unsigned char *buffer, int index);
+int iget(int inode_no, struct ext2_inode *inode);
+void allocate_blocks(struct ext2_inode *file_inode,
+ unsigned int total_remaining_blocks,
+ unsigned int *total_no_of_block);
+void put_ext4(uint64_t off, void *buf, uint32_t size);
+unsigned int be_le(unsigned int num);
+unsigned int le_be(unsigned int num);
#endif
diff --git a/fs/ext4/ext4_journal.c b/fs/ext4/ext4_journal.c
new file mode 100644
index 0000000..fa9c89d
--- /dev/null
+++ b/fs/ext4/ext4_journal.c
@@ -0,0 +1,650 @@
+/*
+ * (C) Copyright 2011 Samsung Electronics
+ * EXT4 filesystem implementation in Uboot by
+ * Uma Shankar <uma.shankar(a)samsung.com>
+ * Manjunatha C Achar <a.manjunatha(a)samsung.com>
+ *
+ * Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+ * 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.
+ */
+
+/*
+ * Journaling feature of ext4 has been referred from JBD2
+ * (Journaling Block device 2) implementation in Linux Kernel
+ */
+#include <common.h>
+#include "ext4_journal.h"
+#include <ext_common.h>
+#include <ext4fs.h>
+#include <malloc.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 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] = (struct journal_log *)xzalloc
+ (sizeof(struct journal_log));
+ if (!journal_ptr[i])
+ goto fail;
+ dirty_block_ptr[i] = (struct dirty_blocks *)
+ xzalloc(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 = (char *)xzalloc(fs->blksz);
+ if (!temp)
+ goto fail;
+ journal_ptr[gindex]->buf = (char *)xzalloc(fs->blksz);
+ if (!journal_ptr[gindex]->buf)
+ goto fail;
+ ext2fs_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 = (char *)xzalloc(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 (check_journal_state(SCAN))
+ goto fail;
+ if (check_journal_state(RECOVER))
+ goto fail;
+ return 0;
+fail:
+ return -1;
+}
+
+void 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) (dirty_block_ptr[i]->blknr * fs->blksz),
+ dirty_block_ptr[i]->buf, (uint32_t) fs->blksz);
+ }
+ return;
+}
+
+void free_journal(void)
+{
+ int i;
+ jrnl_blk_idx = 1;
+ 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;
+ return;
+}
+
+int 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 = (char *)xzalloc(fs->blksz);
+ if (!journal_ptr[gindex]->buf)
+ return -1;
+ 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 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 -1;
+ }
+
+ 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 = (char *)xzalloc(fs->blksz);
+ if (!journal_ptr[gindex]->buf)
+ return -1;
+
+ 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 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 -1;
+ }
+ dirty_block_ptr[gd_index]->buf = (char *)xzalloc(fs->blksz);
+ if (!dirty_block_ptr[gd_index]->buf)
+ return -1;
+ memcpy(dirty_block_ptr[gd_index]->buf, metadata_buffer, fs->blksz);
+ dirty_block_ptr[gd_index++]->blknr = blknr;
+ return 0;
+}
+
+/*------------------------------------*/
+/*Revoke block handling functions*/
+void print_revoke_blks(char *revk_blk)
+{
+ struct journal_revoke_header_t *header;
+ int offset, max;
+ long int blocknr;
+
+ if (revk_blk == NULL)
+ return;
+
+ header = (struct journal_revoke_header_t *) revk_blk;
+ offset = sizeof(struct journal_revoke_header_t);
+ max = be_le(header->r_count);
+ printf("total bytes %d\n", max);
+
+ while (offset < max) {
+ blocknr = be_le(*((long int *)(revk_blk + offset)));
+ printf("revoke blknr is %ld\n", blocknr);
+ offset += 4;
+ }
+ return;
+}
+
+static struct revoke_blk_list *_get_node(void)
+{
+ struct revoke_blk_list *tmp_node;
+ tmp_node = (struct revoke_blk_list *)
+ malloc(sizeof(struct revoke_blk_list));
+ if (tmp_node == NULL)
+ return NULL;
+ tmp_node->content = NULL;
+ tmp_node->next = NULL;
+ return tmp_node;
+}
+
+void push_revoke_blk(char *buffer)
+{
+ struct revoke_blk_list *node;
+ 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 = (char *)malloc(fs->blksz);
+ 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;
+ }
+ return;
+}
+
+void free_revoke_blks()
+{
+ 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;
+ return;
+}
+
+int check_blknr_for_revoke(long int blknr, int sequence_no)
+{
+ struct journal_revoke_header_t *header;
+ int offset, 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 <= be_le(header->r_header.h_sequence)) {
+ offset = sizeof(struct journal_revoke_header_t);
+ max = be_le(header->r_count);
+
+ while (offset < max) {
+ blocknr = be_le(*((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 = (char *)xzalloc(fs->blksz);
+ char *metadata_buff = (char *)xzalloc(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);
+ ext2fs_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 = be_le(tag->flags);
+ if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID))
+ ofs += 16;
+
+ i++;
+ debug("\t\ttag %u\n", be_le(tag->block));
+ if (revk_blk_list != NULL) {
+ if (check_blknr_for_revoke(be_le(tag->block),
+ be_le(jdb->h_sequence)) ==
+ 0) {
+ continue;
+ }
+ }
+ blknr = read_allocated_block(&inode_journal, i);
+ ext2fs_devread(blknr * fs->sect_perblk, 0,
+ fs->blksz, metadata_buff);
+ put_ext4((uint64_t) (be_le(tag->block) * fs->blksz),
+ metadata_buff, (uint32_t) fs->blksz);
+ } while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG));
+fail:
+ if (temp_buff)
+ free(temp_buff);
+ if (metadata_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");
+ return;
+}
+
+int check_journal_state(int recovery_flag)
+{
+ struct ext2_inode inode_journal;
+ struct ext_filesystem *fs = get_fs();
+ struct journal_superblock_t *jsb;
+ struct journal_header_t *jdb;
+ char *p_jdb;
+ 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 ext3_journal_block_tag *tag;
+ char *temp_buff, *temp_buff1;
+
+ temp_buff = (char *)xzalloc(fs->blksz);
+ if (!temp_buff)
+ return -1;
+ temp_buff1 = (char *)xzalloc(fs->blksz);
+ if (!temp_buff1) {
+ free(temp_buff);
+ return -1;
+ }
+
+ ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
+ blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK);
+ ext2fs_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 (be_le(jsb->s_start) == 0)
+ goto END;
+
+ if (!(jsb->s_feature_compat & le_be(JBD2_FEATURE_COMPAT_CHECKSUM)))
+ jsb->s_feature_compat |= le_be(JBD2_FEATURE_COMPAT_CHECKSUM);
+
+ i = be_le(jsb->s_first);
+ while (1) {
+ block = be_le(jsb->s_first);
+ blknr = read_allocated_block(&inode_journal, i);
+ memset(temp_buff1, '\0', fs->blksz);
+ ext2fs_devread(blknr * fs->sect_perblk,
+ 0, fs->blksz, temp_buff1);
+ jdb = (struct journal_header_t *) temp_buff1;
+
+ if (be_le(jdb->h_blocktype) == EXT3_JOURNAL_DESCRIPTOR_BLOCK) {
+ if (be_le(jdb->h_sequence) != be_le(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 = be_le(tag->flags);
+ if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID))
+ ofs += 16;
+ i++;
+ debug("\t\ttag %u\n", be_le(tag->block));
+ } while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG));
+ i++;
+ DB_FOUND = YES;
+ } else if (be_le(jdb->h_blocktype) ==
+ EXT3_JOURNAL_COMMIT_BLOCK) {
+ if ((be_le(jdb->h_sequence) != be_le(jsb->s_sequence))
+ || (DB_FOUND == NO)) {
+ print_jrnl_status(recovery_flag);
+ break;
+ }
+
+ if (transaction_state == TRANSACTION_RUNNING) {
+ transaction_state = TRANSACTION_COMPLETE;
+ i++;
+ jsb->s_sequence =
+ le_be(be_le(jsb->s_sequence) + 1);
+ }
+ prev_desc_logical_no = curr_desc_logical_no;
+ recover_transaction(prev_desc_logical_no);
+ DB_FOUND = NO;
+ } else if (be_le(jdb->h_blocktype) ==
+ EXT3_JOURNAL_REVOKE_BLOCK) {
+ if (be_le(jdb->h_sequence) != be_le(jsb->s_sequence)) {
+ print_jrnl_status(recovery_flag);
+ break;
+ }
+ if (recovery_flag == SCAN)
+ push_revoke_blk((char *)jdb);
+ i++;
+ } else {
+ debug("Else Case\n");
+ if (be_le(jdb->h_sequence) != be_le(jsb->s_sequence)) {
+ print_jrnl_status(recovery_flag);
+ break;
+ }
+ }
+ }
+
+END:
+ if (recovery_flag == RECOVER) {
+ jsb->s_start = le_be(1);
+ jsb->s_sequence = le_be(be_le(jsb->s_sequence) + 1);
+ ext2fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE,
+ (char *)fs->sb);
+ fs->sb->feature_incompat |= EXT3_FEATURE_INCOMPAT_RECOVER;
+
+ put_ext4((uint64_t) (SUPERBLOCK_SIZE),
+ (struct ext2_sblock *)fs->sb,
+ (uint32_t) SUPERBLOCK_SIZE);
+ ext2fs_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);
+ free_revoke_blks();
+ }
+ free(temp_buff);
+ free(temp_buff1);
+
+ return 0;
+}
+
+static void update_descriptor_block(long int blknr)
+{
+ struct journal_header_t jdb;
+ struct ext3_journal_block_tag tag;
+ struct ext2_inode inode_journal;
+ struct journal_superblock_t *jsb;
+ long int jsb_blknr;
+ struct ext_filesystem *fs = get_fs();
+ char *buf = NULL, *temp = NULL;
+ int i;
+ char *temp_buff = (char *)xzalloc(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);
+ ext2fs_devread(jsb_blknr * fs->sect_perblk, 0, fs->blksz, temp_buff);
+ jsb = (struct journal_superblock_t *) temp_buff;
+
+ jdb.h_blocktype = le_be(EXT3_JOURNAL_DESCRIPTOR_BLOCK);
+ jdb.h_magic = le_be(EXT3_JOURNAL_MAGIC_NUMBER);
+ jdb.h_sequence = jsb->s_sequence;
+ buf = (char *)xzalloc(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 = le_be(journal_ptr[i]->blknr);
+ tag.flags = le_be(EXT3_JOURNAL_FLAG_SAME_UUID);
+ memcpy(temp, &tag, sizeof(struct ext3_journal_block_tag));
+ temp = temp + sizeof(struct ext3_journal_block_tag);
+ }
+
+ tag.block = le_be(journal_ptr[--i]->blknr);
+ tag.flags = le_be(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 = (char *)xzalloc(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);
+ ext2fs_devread(jsb_blknr * fs->sect_perblk, 0, fs->blksz, temp_buff);
+ jsb = (struct journal_superblock_t *) temp_buff;
+
+ jdb.h_blocktype = le_be(EXT3_JOURNAL_COMMIT_BLOCK);
+ jdb.h_magic = le_be(EXT3_JOURNAL_MAGIC_NUMBER);
+ jdb.h_sequence = jsb->s_sequence;
+ buf = (char *)xzalloc(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 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) (blknr * fs->blksz),
+ journal_ptr[i]->buf, (uint32_t) fs->blksz);
+ }
+ blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++);
+ update_commit_block(blknr);
+ printf("update journal finished\n");
+}
diff --git a/fs/ext4/ext4_journal.h b/fs/ext4/ext4_journal.h
new file mode 100644
index 0000000..e4413d2
--- /dev/null
+++ b/fs/ext4/ext4_journal.h
@@ -0,0 +1,147 @@
+/*
+ * (C) Copyright 2011 Samsung Electronics
+ * EXT4 filesystem implementation in Uboot by
+ * Uma Shankar <uma.shankar(a)samsung.com>
+ * Manjunatha C Achar <a.manjunatha(a)samsung.com>
+ *
+ * Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+ * 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.
+ */
+
+/*
+ * Journaling feature of ext4 has been referred from JBD2
+ * (Journaling Block device 2) implementation in Linux Kernel
+ */
+
+#ifndef __EXT4_JRNL__
+#define __EXT4_JRNL__
+
+#include "ext4_common.h"
+
+#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;
+
+ /* 0x000C */
+ /* 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 */
+
+ /* 0x0018 */
+ /* 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 */
+
+ /* 0x0020 */
+ /* Error value, as set by journal_abort(). */
+ __s32 s_errno;
+
+ /* 0x0024 */
+ /* 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 init_journal(void);
+void deinit_journal(void);
+int log_gdt(char *gd_table);
+void update_journal(void);
+int check_journal_state(int recovery_flag);
+int log_journal(char *journal_buffer, long int blknr);
+int put_metadata(char *metadata_buffer, long int blknr);
+void dump_metadata(void);
+void free_journal(void);
+void free_revoke_blks(void);
+void push_revoke_blk(char *buffer);
+#endif
diff --git a/fs/ext4/ext4fs.c b/fs/ext4/ext4fs.c
index d4faa16..0a033aa 100644
--- a/fs/ext4/ext4fs.c
+++ b/fs/ext4/ext4fs.c
@@ -22,7 +22,13 @@
/*
* ext4load - based on code from GRUB2 fs/ext2.c
-*/
+ *
+ * ext4write - based on existing ext2 support in UBOOT and ext4
+ * implementation in Linux Kernel.
+ * Journaling feature of ext4 has been referred from JBD2
+ * (Journaling Block device 2) implementation in Linux Kernel
+ */
+
#include <common.h>
#include <malloc.h>
#include <asm/byteorder.h>
@@ -31,6 +37,7 @@
#include <ext_common.h>
#include <ext4fs.h>
#include "ext4_common.h"
+#include "ext4_journal.h"
int ext4fs_symlinknest;
block_dev_desc_t *ext4_dev_desc;
@@ -213,3 +220,1032 @@ int ext4fs_read(char *buf, unsigned len)
return 0;
return ext4fs_read_file(ext4fs_file, 0, len, buf);
}
+
+static void ext4fs_update(void)
+{
+ short i;
+ update_journal();
+ struct ext_filesystem *fs = get_fs();
+
+ /*Update the super block */
+ put_ext4((uint64_t) (SUPERBLOCK_SIZE),
+ (struct ext2_sblock *)fs->sb, (uint32_t) SUPERBLOCK_SIZE);
+
+ /*update the block group */
+ for (i = 0; i < fs->no_blkgrp; i++) {
+ fs->gd[i].bg_checksum = ext4fs_checksum_update(i);
+ put_ext4((uint64_t) (fs->gd[i].block_id * fs->blksz),
+ fs->blk_bmaps[i], (uint32_t) fs->blksz);
+ }
+
+ /*update the inode table group */
+ for (i = 0; i < fs->no_blkgrp; i++) {
+ put_ext4((uint64_t) (fs->gd[i].inode_id * fs->blksz),
+ fs->inode_bmaps[i], (uint32_t) fs->blksz);
+ }
+
+ /*update the block group descriptor table */
+ put_ext4((uint64_t) (fs->gdtable_blkno * fs->blksz),
+ (struct ext2_block_group *)fs->gdtable, (uint32_t)
+ (fs->blksz * fs->no_blk_pergdt));
+
+ dump_metadata();
+
+ gindex = 0;
+ gd_index = 0;
+}
+
+int ext4fs_get_bgdtable(void)
+{
+ int status;
+ int grp_desc_size;
+ struct ext_filesystem *fs = get_fs();
+ grp_desc_size = sizeof(struct ext2_block_group);
+ fs->no_blk_pergdt = (fs->no_blkgrp * grp_desc_size) / fs->blksz;
+ if ((fs->no_blkgrp * grp_desc_size) % fs->blksz)
+ fs->no_blk_pergdt++;
+
+ /*allocate mem for gdtable */
+ fs->gdtable = (char *)xzalloc(fs->blksz * fs->no_blk_pergdt);
+ if (!fs->gdtable)
+ return -1;
+ /*Read the first group descriptor table */
+ status = ext2fs_devread(fs->gdtable_blkno * fs->sect_perblk, 0,
+ fs->blksz * fs->no_blk_pergdt, fs->gdtable);
+ if (status == 0)
+ goto fail;
+
+ if (log_gdt(fs->gdtable)) {
+ printf("Error in log_gdt\n");
+ return -1;
+ }
+
+ return 0;
+fail:
+ if (fs->gdtable) {
+ free(fs->gdtable);
+ fs->gdtable = NULL;
+ }
+ return -1;
+}
+
+static void delete_single_indirect_block(struct ext2_inode *inode)
+{
+ struct ext2_block_group *gd;
+ static int prev_bg_bitmap_index = -1;
+ long int blknr;
+ int remainder;
+ int bg_idx;
+ int status;
+ struct ext_filesystem *fs = get_fs();
+ char *journal_buffer = (char *)xzalloc(fs->blksz);
+ if (!journal_buffer)
+ return;
+ /*get the block group descriptor table */
+ gd = (struct ext2_block_group *)fs->gdtable;
+
+ /*deleting the single indirect block associated with inode */
+ if (inode->b.blocks.indir_block != 0) {
+ debug("SIPB releasing %u\n", inode->b.blocks.indir_block);
+ blknr = inode->b.blocks.indir_block;
+ if (fs->blksz != 1024) {
+ bg_idx = blknr / (uint32_t)
+ ext4fs_root->sblock.blocks_per_group;
+ } else {
+ bg_idx = blknr /
+ (uint32_t) ext4fs_root->sblock.blocks_per_group;
+ remainder = blknr % (uint32_t)
+ ext4fs_root->sblock.blocks_per_group;
+ if (!remainder)
+ bg_idx--;
+ }
+ reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
+ gd[bg_idx].free_blocks++;
+ fs->sb->free_blocks++;
+ /*journal backup */
+ if (prev_bg_bitmap_index != bg_idx) {
+ status =
+ ext2fs_devread(gd[bg_idx].block_id *
+ fs->sect_perblk, 0, fs->blksz,
+ journal_buffer);
+ if (status == 0)
+ goto fail;
+ if (log_journal(journal_buffer, gd[bg_idx].block_id))
+ goto fail;
+ prev_bg_bitmap_index = bg_idx;
+ }
+ }
+fail:
+ if (journal_buffer)
+ free(journal_buffer);
+ return;
+
+}
+
+/*deleting the double indirect blocks */
+static void delete_double_indirect_block(struct ext2_inode *inode)
+{
+ int i;
+ short status;
+ static int prev_bg_bitmap_index = -1;
+ long int blknr;
+ int remainder;
+ int bg_idx;
+ unsigned int *double_indirect_buffer;
+ unsigned int *DIB_start_addr = NULL;
+ struct ext2_block_group *gd;
+ struct ext_filesystem *fs = get_fs();
+ char *journal_buffer = (char *)xzalloc(fs->blksz);
+ if (!journal_buffer)
+ return;
+ /*get the block group descriptor table */
+ gd = (struct ext2_block_group *)fs->gdtable;
+
+ if (inode->b.blocks.double_indir_block != 0) {
+ double_indirect_buffer = (unsigned int *)xzalloc(fs->blksz);
+ if (!double_indirect_buffer)
+ return;
+ DIB_start_addr = (unsigned int *)double_indirect_buffer;
+ blknr = inode->b.blocks.double_indir_block;
+ status = ext2fs_devread(blknr * fs->sect_perblk, 0, fs->blksz,
+ (char *)double_indirect_buffer);
+ for (i = 0; i < fs->blksz / sizeof(int); i++) {
+ if (*double_indirect_buffer == 0)
+ break;
+
+ debug("DICB releasing %u\n", *double_indirect_buffer);
+ if (fs->blksz != 1024) {
+ bg_idx = (*double_indirect_buffer) /
+ (uint32_t) ext4fs_root->sblock.
+ blocks_per_group;
+ } else {
+ bg_idx = (*double_indirect_buffer) /
+ (uint32_t) ext4fs_root->sblock.
+ blocks_per_group;
+ remainder =
+ (*double_indirect_buffer) %
+ (uint32_t) ext4fs_root->sblock.
+ blocks_per_group;
+ if (!remainder)
+ bg_idx--;
+ }
+ reset_block_bmap(*double_indirect_buffer,
+ fs->blk_bmaps[bg_idx], bg_idx);
+ double_indirect_buffer++;
+ gd[bg_idx].free_blocks++;
+ fs->sb->free_blocks++;
+ /*journal backup */
+ if (prev_bg_bitmap_index != bg_idx) {
+ status = ext2fs_devread(gd[bg_idx].block_id
+ * fs->sect_perblk, 0,
+ fs->blksz,
+ journal_buffer);
+ if (status == 0)
+ goto fail;
+
+ if (log_journal(journal_buffer,
+ gd[bg_idx].block_id))
+ goto fail;
+ prev_bg_bitmap_index = bg_idx;
+ }
+ }
+
+ /*removing the parent double indirect block */
+ /*find the bitmap index */
+ blknr = inode->b.blocks.double_indir_block;
+ if (fs->blksz != 1024) {
+ bg_idx = blknr / (uint32_t)
+ ext4fs_root->sblock.blocks_per_group;
+ } else {
+ bg_idx = blknr /
+ (uint32_t) ext4fs_root->sblock.blocks_per_group;
+ remainder =
+ blknr %
+ (uint32_t) ext4fs_root->sblock.blocks_per_group;
+ if (!remainder)
+ bg_idx--;
+ }
+ reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
+ gd[bg_idx].free_blocks++;
+ fs->sb->free_blocks++;
+ /*journal backup */
+ if (prev_bg_bitmap_index != bg_idx) {
+ memset(journal_buffer, '\0', fs->blksz);
+ status = ext2fs_devread(gd[bg_idx].block_id *
+ fs->sect_perblk, 0, fs->blksz,
+ journal_buffer);
+ if (status == 0)
+ goto fail;
+
+ if (log_journal(journal_buffer, gd[bg_idx].block_id))
+ goto fail;
+ prev_bg_bitmap_index = bg_idx;
+ }
+ debug("DIPB releasing %ld\n", blknr);
+ }
+fail:
+ if (DIB_start_addr)
+ free(DIB_start_addr);
+ if (journal_buffer)
+ free(journal_buffer);
+ return;
+}
+
+/*deleting the triple indirect blocks */
+static void delete_triple_indirect_block(struct ext2_inode *inode)
+{
+ int i, j;
+ short status;
+ static int prev_bg_bitmap_index = -1;
+ long int blknr;
+ int remainder;
+ int bg_idx;
+ unsigned int *TIGP_buffer = NULL;
+ unsigned int *TIB_start_addr = NULL;
+ unsigned int *TIP_buffer = NULL;
+ unsigned int *TIPB_start_addr = NULL;
+ struct ext2_block_group *gd;
+ struct ext_filesystem *fs = get_fs();
+ char *journal_buffer = (char *)xzalloc(fs->blksz);
+ if (!journal_buffer)
+ return;
+ /*get the block group descriptor table */
+ gd = (struct ext2_block_group *)fs->gdtable;
+
+ if (inode->b.blocks.tripple_indir_block != 0) {
+ TIGP_buffer = (unsigned int *)xzalloc(fs->blksz);
+ if (!TIGP_buffer)
+ return;
+ TIB_start_addr = (unsigned int *)TIGP_buffer;
+ blknr = inode->b.blocks.tripple_indir_block;
+ status = ext2fs_devread(blknr * fs->sect_perblk, 0, fs->blksz,
+ (char *)TIGP_buffer);
+ for (i = 0; i < fs->blksz / sizeof(int); i++) {
+ if (*TIGP_buffer == 0)
+ break;
+ debug("TIGPB releasing %u\n", *TIGP_buffer);
+
+ TIP_buffer = (unsigned int *)xzalloc(fs->blksz);
+ if (!TIP_buffer)
+ goto fail;
+ TIPB_start_addr = (unsigned int *)TIP_buffer;
+ status = ext2fs_devread((*TIGP_buffer) *
+ fs->sect_perblk, 0, fs->blksz,
+ (char *)TIP_buffer);
+ for (j = 0; j < fs->blksz / sizeof(int); j++) {
+ if (*TIP_buffer == 0)
+ break;
+ if (fs->blksz != 1024) {
+ bg_idx = (*TIP_buffer) / (uint32_t)
+ ext4fs_root->sblock.
+ blocks_per_group;
+ } else {
+ bg_idx = (*TIP_buffer) / (uint32_t)
+ ext4fs_root->sblock.
+ blocks_per_group;
+
+ remainder = (*TIP_buffer) % (uint32_t)
+ ext4fs_root->sblock.
+ blocks_per_group;
+ if (!remainder)
+ bg_idx--;
+ }
+
+ reset_block_bmap(*TIP_buffer,
+ fs->blk_bmaps[bg_idx], bg_idx);
+
+ TIP_buffer++;
+ gd[bg_idx].free_blocks++;
+ fs->sb->free_blocks++;
+ /*journal backup */
+ if (prev_bg_bitmap_index != bg_idx) {
+ status =
+ ext2fs_devread(gd[bg_idx].block_id *
+ fs->sect_perblk, 0,
+ fs->blksz,
+ journal_buffer);
+ if (status == 0)
+ goto fail;
+
+ if (log_journal(journal_buffer,
+ gd[bg_idx].block_id))
+ goto fail;
+ prev_bg_bitmap_index = bg_idx;
+ }
+ }
+ if (TIPB_start_addr) {
+ free(TIPB_start_addr);
+ TIPB_start_addr = NULL;
+ }
+
+ /*removing the grand parent blocks
+ *which is connected to inode
+ */
+ if (fs->blksz != 1024) {
+ bg_idx = (*TIGP_buffer) / (uint32_t)
+ ext4fs_root->sblock.blocks_per_group;
+ } else {
+ bg_idx = (*TIGP_buffer) / (uint32_t)
+ ext4fs_root->sblock.blocks_per_group;
+
+ remainder = (*TIGP_buffer) % (uint32_t)
+ ext4fs_root->sblock.blocks_per_group;
+ if (!remainder)
+ bg_idx--;
+ }
+ reset_block_bmap(*TIGP_buffer,
+ fs->blk_bmaps[bg_idx], bg_idx);
+
+ TIGP_buffer++;
+ gd[bg_idx].free_blocks++;
+ fs->sb->free_blocks++;
+ /*journal backup */
+ if (prev_bg_bitmap_index != bg_idx) {
+ memset(journal_buffer, '\0', fs->blksz);
+ status =
+ ext2fs_devread(gd[bg_idx].block_id *
+ fs->sect_perblk, 0,
+ fs->blksz, journal_buffer);
+ if (status == 0)
+ goto fail;
+
+ if (log_journal(journal_buffer,
+ gd[bg_idx].block_id))
+ goto fail;
+ prev_bg_bitmap_index = bg_idx;
+ }
+ }
+
+ /*removing the grand parent triple indirect block */
+ /*find the bitmap index */
+ blknr = inode->b.blocks.tripple_indir_block;
+ if (fs->blksz != 1024) {
+ bg_idx = blknr / (uint32_t)
+ ext4fs_root->sblock.blocks_per_group;
+ } else {
+ bg_idx = blknr / (uint32_t)
+ ext4fs_root->sblock.blocks_per_group;
+ remainder = blknr % (uint32_t)
+ ext4fs_root->sblock.blocks_per_group;
+ if (!remainder)
+ bg_idx--;
+ }
+ reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
+ gd[bg_idx].free_blocks++;
+ fs->sb->free_blocks++;
+ /*journal backup */
+ if (prev_bg_bitmap_index != bg_idx) {
+ memset(journal_buffer, '\0', fs->blksz);
+ status = ext2fs_devread(gd[bg_idx].block_id
+ * fs->sect_perblk, 0, fs->blksz,
+ journal_buffer);
+ if (status == 0)
+ goto fail;
+
+ if (log_journal(journal_buffer, gd[bg_idx].block_id))
+ goto fail;
+ prev_bg_bitmap_index = bg_idx;
+ }
+ debug("TIGPB iteself releasing %ld\n", blknr);
+ }
+fail:
+ if (TIB_start_addr)
+ free(TIB_start_addr);
+ if (TIPB_start_addr)
+ free(TIPB_start_addr);
+ if (journal_buffer)
+ free(journal_buffer);
+ return;
+}
+
+static int ext4fs_delete_file(int inodeno)
+{
+ struct ext2_inode inode;
+ short status;
+ int i;
+ int remainder;
+ long int blknr;
+ int bg_idx;
+ int inode_bitmap_index;
+ char *read_buffer;
+ char *start_block_address = NULL;
+ unsigned int no_blocks;
+
+ static int prev_bg_bitmap_index = -1;
+ unsigned int inodes_per_block;
+ long int blkno;
+ unsigned int blkoff;
+ struct ext2_inode *inode_buffer;
+ struct ext2_block_group *gd;
+ struct ext_filesystem *fs = get_fs();
+ char *journal_buffer = (char *)xzalloc(fs->blksz);
+ if (!journal_buffer)
+ return -1;
+ /*get the block group descriptor table */
+ gd = (struct ext2_block_group *)fs->gdtable;
+ status = ext4fs_read_inode(ext4fs_root, inodeno, &inode);
+ if (status == 0)
+ goto fail;
+
+ /*read the block no allocated to a file */
+ no_blocks = inode.size / fs->blksz;
+ if (inode.size % fs->blksz)
+ no_blocks++;
+
+ if (le32_to_cpu(inode.flags) & EXT4_EXTENTS_FLAG) {
+ struct ext2fs_node *node_inode =
+ (struct ext2fs_node *) xzalloc(sizeof(struct ext2fs_node));
+ if (!node_inode)
+ goto fail;
+ node_inode->data = ext4fs_root;
+ node_inode->ino = inodeno;
+ node_inode->inode_read = 0;
+ memcpy(&(node_inode->inode), &inode, sizeof(struct ext2_inode));
+
+ for (i = 0; i < no_blocks; i++) {
+ blknr = read_allocated_block(&(node_inode->inode), i);
+ if (fs->blksz != 1024) {
+ bg_idx = blknr / (uint32_t)
+ ext4fs_root->sblock.blocks_per_group;
+ } else {
+ bg_idx = blknr / (uint32_t)
+ ext4fs_root->sblock.blocks_per_group;
+ remainder = blknr % (uint32_t)
+ ext4fs_root->sblock.blocks_per_group;
+ if (!remainder)
+ bg_idx--;
+ }
+ reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
+ debug("EXT4_EXTENTS Block releasing %ld: %d\n",
+ blknr, bg_idx);
+
+ gd[bg_idx].free_blocks++;
+ fs->sb->free_blocks++;
+
+ /*journal backup */
+ if (prev_bg_bitmap_index != bg_idx) {
+ status =
+ ext2fs_devread(gd[bg_idx].block_id *
+ fs->sect_perblk, 0,
+ fs->blksz, journal_buffer);
+ if (status == 0)
+ goto fail;
+ if (log_journal(journal_buffer,
+ gd[bg_idx].block_id))
+ goto fail;
+ prev_bg_bitmap_index = bg_idx;
+ }
+ }
+ if (node_inode) {
+ free(node_inode);
+ node_inode = NULL;
+ }
+ } else {
+ /*deleting the single indirect block associated with inode */
+ delete_single_indirect_block(&inode);
+
+ /*deleting the double indirect blocks */
+ delete_double_indirect_block(&inode);
+
+ /*deleting the triple indirect blocks */
+ delete_triple_indirect_block(&inode);
+
+ /*read the block no allocated to a file */
+ no_blocks = inode.size / fs->blksz;
+ if (inode.size % fs->blksz)
+ no_blocks++;
+ for (i = 0; i < no_blocks; i++) {
+ blknr = read_allocated_block(&inode, i);
+ if (fs->blksz != 1024) {
+ bg_idx = blknr /
+ (uint32_t) ext4fs_root->sblock.
+ blocks_per_group;
+ } else {
+ bg_idx =
+ blknr /
+ (uint32_t) ext4fs_root->sblock.
+ blocks_per_group;
+ remainder = blknr % (uint32_t)
+ ext4fs_root->sblock.blocks_per_group;
+ if (!remainder)
+ bg_idx--;
+ }
+ reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
+ debug("ActualB releasing %ld: %d\n", blknr, bg_idx);
+
+ gd[bg_idx].free_blocks++;
+ fs->sb->free_blocks++;
+ /*journal backup */
+ if (prev_bg_bitmap_index != bg_idx) {
+ memset(journal_buffer, '\0', fs->blksz);
+ status = ext2fs_devread(gd[bg_idx].block_id
+ * fs->sect_perblk,
+ 0, fs->blksz,
+ journal_buffer);
+ if (status == 0) {
+ free(journal_buffer);
+ goto fail;
+ }
+ if (log_journal(journal_buffer,
+ gd[bg_idx].block_id))
+ goto fail;
+ prev_bg_bitmap_index = bg_idx;
+ }
+ }
+ }
+
+ /*from the inode no to blockno */
+ inodes_per_block = EXT2_BLOCK_SIZE(ext4fs_root) / fs->inodesz;
+ inode_bitmap_index = inodeno /
+ (uint32_t) ext4fs_root->sblock.inodes_per_group;
+
+ /*get the block no */
+ inodeno--;
+ blkno = __le32_to_cpu(gd[inode_bitmap_index].inode_table_id) +
+ (inodeno % __le32_to_cpu(ext4fs_root->sblock.inodes_per_group))
+ / inodes_per_block;
+
+ /*get the offset of the inode */
+ blkoff = ((inodeno) % inodes_per_block) * fs->inodesz;
+
+ /*read the block no containing the inode */
+ read_buffer = (char *)xzalloc(fs->blksz);
+ if (!read_buffer)
+ goto fail;
+ start_block_address = read_buffer;
+ status = ext2fs_devread(blkno * fs->sect_perblk,
+ 0, fs->blksz, read_buffer);
+ if (status == 0)
+ goto fail;
+
+ if (log_journal(read_buffer, blkno))
+ goto fail;
+
+ read_buffer = read_buffer + blkoff;
+ inode_buffer = (struct ext2_inode *)read_buffer;
+ memset(inode_buffer, '\0', sizeof(struct ext2_inode));
+
+ /*write the inode to original position in inode table */
+ if (put_metadata(start_block_address, blkno))
+ goto fail;
+
+ /*update the respective inode bitmaps */
+ inodeno++;
+ reset_inode_bmap(inodeno, fs->inode_bmaps
+ [inode_bitmap_index], inode_bitmap_index);
+ gd[inode_bitmap_index].free_inodes++;
+ fs->sb->free_inodes++;
+ /*journal backup */
+ memset(journal_buffer, '\0', fs->blksz);
+ status = ext2fs_devread(gd[inode_bitmap_index].inode_id *
+ fs->sect_perblk, 0, fs->blksz, journal_buffer);
+ if (status == 0)
+ goto fail;
+ if (log_journal(journal_buffer, gd[inode_bitmap_index].inode_id))
+ goto fail;
+
+ ext4fs_update();
+ ext4fs_deinit();
+
+ if (ext4fs_init() != 0) {
+ printf("error in File System init\n");
+ goto fail;
+ }
+
+ /*free */
+ if (start_block_address)
+ free(start_block_address);
+ if (journal_buffer)
+ free(journal_buffer);
+ return 0;
+
+fail:
+ if (start_block_address)
+ free(start_block_address);
+ if (journal_buffer)
+ free(journal_buffer);
+ return -1;
+}
+
+int ext4fs_init(void)
+{
+ short status;
+ int i;
+ int sector_per_block;
+ unsigned int real_free_blocks = 0;
+ struct ext_filesystem *fs = get_fs();
+
+ /*populate fs */
+ fs->blksz = EXT2_BLOCK_SIZE(ext4fs_root);
+ fs->inodesz = INODE_SIZE_FILESYSTEM(ext4fs_root);
+ fs->sect_perblk = fs->blksz / SECTOR_SIZE;
+
+ sector_per_block = fs->sect_perblk;
+ /*get the superblock */
+ fs->sb = (struct ext2_sblock *)xzalloc(SUPERBLOCK_SIZE);
+ if (!fs->sb)
+ return -1;
+ status = ext2fs_devread(SUPERBLOCK_SECTOR, 0,
+ SUPERBLOCK_SIZE, (char *)fs->sb);
+ if (status == 0)
+ goto fail;
+
+ /*init journal */
+ if (init_journal())
+ goto fail;
+
+ /*get the no of blockgroups */
+
+ fs->no_blkgrp = (uint32_t) ext4fs_div_roundup
+ ((uint32_t) (ext4fs_root->sblock.total_blocks
+ - ext4fs_root->sblock.first_data_block),
+ (uint32_t) ext4fs_root->sblock.blocks_per_group);
+
+ /*get the block group descriptor table */
+ fs->gdtable_blkno = ((EXT2_MIN_BLOCK_SIZE == fs->blksz) + 1);
+ if (ext4fs_get_bgdtable() == -1) {
+ printf("*Eror in getting the block group descriptor table\n");
+ goto fail;
+ } else {
+ fs->gd = (struct ext2_block_group *)fs->gdtable;
+ }
+
+ /*load all the available bitmap block of the partition */
+ fs->blk_bmaps = (unsigned char **)xzalloc
+ (fs->no_blkgrp * sizeof(unsigned char *));
+ if (!fs->blk_bmaps)
+ goto fail;
+ for (i = 0; i < fs->no_blkgrp; i++) {
+ fs->blk_bmaps[i] = (unsigned char *)xzalloc(fs->blksz);
+ if (!fs->blk_bmaps[i])
+ goto fail;
+ }
+
+ for (i = 0; i < fs->no_blkgrp; i++) {
+ status =
+ ext2fs_devread(fs->gd[i].block_id * sector_per_block, 0,
+ fs->blksz, (char *)fs->blk_bmaps[i]);
+ if (status == 0)
+ goto fail;
+ }
+
+ /*load all the available inode bitmap of the partition */
+ fs->inode_bmaps = (unsigned char **)xzalloc
+ (fs->no_blkgrp * sizeof(unsigned char *));
+ if (!fs->inode_bmaps)
+ goto fail;
+ for (i = 0; i < fs->no_blkgrp; i++) {
+ fs->inode_bmaps[i] = (unsigned char *)xzalloc(fs->blksz);
+ if (!fs->inode_bmaps[i])
+ goto fail;
+ }
+
+ for (i = 0; i < fs->no_blkgrp; i++) {
+ status = ext2fs_devread(fs->gd[i].inode_id * sector_per_block,
+ 0, fs->blksz,
+ (char *)fs->inode_bmaps[i]);
+ if (status == 0)
+ goto fail;
+ }
+
+ /*
+ *check filesystem consistency with free blocks of file system
+ *some time we observed that superblock freeblocks does not match
+ *with the blockgroups freeblocks when improper
+ *reboot of a linux kernel
+ */
+ for (i = 0; i < fs->no_blkgrp; i++)
+ real_free_blocks = real_free_blocks + fs->gd[i].free_blocks;
+ if (real_free_blocks != fs->sb->free_blocks)
+ fs->sb->free_blocks = real_free_blocks;
+ return 0;
+
+fail:
+ ext4fs_deinit();
+ return -1;
+}
+
+void ext4fs_deinit(void)
+{
+ int i;
+ struct ext2_inode inode_journal;
+ struct journal_superblock_t *jsb;
+ long int blknr;
+ struct ext_filesystem *fs = get_fs();
+ /*free journal */
+ char *temp_buff = (char *)xzalloc(fs->blksz);
+ if (temp_buff) {
+ ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
+ &inode_journal);
+ blknr =
+ read_allocated_block(&inode_journal,
+ EXT2_JOURNAL_SUPERBLOCK);
+ ext2fs_devread(blknr * fs->sect_perblk, 0, fs->blksz,
+ temp_buff);
+ jsb = (struct journal_superblock_t *)temp_buff;
+ jsb->s_start = le_be(0);
+ put_ext4((uint64_t) (blknr * fs->blksz),
+ (struct journal_superblock_t *)temp_buff,
+ (uint32_t) fs->blksz);
+ free(temp_buff);
+ }
+ free_journal();
+ /*get the superblock */
+ ext2fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE, (char *)fs->sb);
+ fs->sb->feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
+ put_ext4((uint64_t) (SUPERBLOCK_SIZE),
+ (struct ext2_sblock *)fs->sb, (uint32_t) SUPERBLOCK_SIZE);
+ if (fs->sb) {
+ free(fs->sb);
+ fs->sb = NULL;
+ }
+
+ if (fs->blk_bmaps) {
+ for (i = 0; i < fs->no_blkgrp; i++) {
+ if (fs->blk_bmaps[i]) {
+ free(fs->blk_bmaps[i]);
+ fs->blk_bmaps[i] = NULL;
+ }
+ }
+ free(fs->blk_bmaps);
+ fs->blk_bmaps = NULL;
+ }
+
+ if (fs->inode_bmaps) {
+ for (i = 0; i < fs->no_blkgrp; i++) {
+ if (fs->inode_bmaps[i]) {
+ free(fs->inode_bmaps[i]);
+ fs->inode_bmaps[i] = NULL;
+ }
+ }
+ free(fs->inode_bmaps);
+ fs->inode_bmaps = NULL;
+ }
+
+ if (fs->gdtable) {
+ free(fs->gdtable);
+ fs->gdtable = NULL;
+ }
+ fs->gd = NULL;
+ /*
+ *Reinitiliazed the global inode and
+ *block bitmap first execution check variables
+ */
+ fs->first_pass_ibmap = 0;
+ fs->first_pass_bbmap = 0;
+ fs->curr_inode_no = 0;
+ fs->curr_blkno = 0;
+
+ return;
+}
+
+static int ext4fs_write_file(struct ext2_inode *file_inode,
+ int pos, unsigned int len, char *buf)
+{
+ int i;
+ int blockcnt;
+ int log2blocksize = LOG2_EXT2_BLOCK_SIZE(ext4fs_root);
+ unsigned int filesize = __le32_to_cpu(file_inode->size);
+ struct ext_filesystem *fs = get_fs();
+ int previous_block_number = -1;
+ int delayed_start = 0;
+ int delayed_extent = 0;
+ int delayed_skipfirst = 0;
+ int delayed_next = 0;
+ char *delayed_buf = NULL;
+
+ /* Adjust len so it we can't read past the end of the file. */
+ if (len > filesize)
+ len = filesize;
+
+ blockcnt = ((len + pos) + fs->blksz - 1) / fs->blksz;
+
+ for (i = pos / fs->blksz; i < blockcnt; i++) {
+ long int blknr;
+ int blockend = fs->blksz;
+ int skipfirst = 0;
+ blknr = read_allocated_block(file_inode, i);
+ if (blknr < 0)
+ return -1;
+
+ blknr = blknr << log2blocksize;
+
+ if (blknr) {
+ if (previous_block_number != -1) {
+ if (delayed_next == blknr) {
+ delayed_extent += blockend;
+ delayed_next += blockend >> SECTOR_BITS;
+ } else { /* spill */
+ put_ext4((uint64_t) (delayed_start *
+ SECTOR_SIZE),
+ delayed_buf,
+ (uint32_t) delayed_extent);
+ previous_block_number = blknr;
+ delayed_start = blknr;
+ delayed_extent = blockend;
+ delayed_skipfirst = skipfirst;
+ delayed_buf = buf;
+ delayed_next = blknr +
+ (blockend >> SECTOR_BITS);
+ }
+ } else {
+ previous_block_number = blknr;
+ delayed_start = blknr;
+ delayed_extent = blockend;
+ delayed_skipfirst = skipfirst;
+ delayed_buf = buf;
+ delayed_next = blknr +
+ (blockend >> SECTOR_BITS);
+ }
+ } else {
+ if (previous_block_number != -1) {
+ /* spill */
+ put_ext4((uint64_t) (delayed_start *
+ SECTOR_SIZE), delayed_buf,
+ (uint32_t) delayed_extent);
+ previous_block_number = -1;
+ }
+ memset(buf, 0, fs->blksz - skipfirst);
+ }
+ buf += fs->blksz - skipfirst;
+ }
+ if (previous_block_number != -1) {
+ /* spill */
+ put_ext4((uint64_t) (delayed_start * SECTOR_SIZE),
+ delayed_buf, (uint32_t) delayed_extent);
+ previous_block_number = -1;
+ }
+ return len;
+}
+
+int ext4fs_write(char *fname, unsigned char *buffer, unsigned long sizebytes)
+{
+ int ret = 0;
+ /*inode */
+ struct ext2_inode *file_inode = NULL;
+ unsigned char *inode_buffer = NULL;
+ int parent_inodeno;
+ int inodeno;
+ time_t timestamp = 0;
+
+ /*filesize */
+ uint64_t total_no_of_bytes_for_file;
+ unsigned int total_no_of_block_for_file;
+ unsigned int total_remaining_blocks;
+ int existing_file_inodeno;
+ char filename[256];
+
+ char *temp_ptr = NULL;
+ long int itable_blkno, parent_itable_blkno, blkoff;
+ struct ext2_sblock *sblock = &(ext4fs_root->sblock);
+ unsigned int inodes_per_block;
+ unsigned int inode_bitmap_index;
+ struct ext_filesystem *fs = get_fs();
+
+ g_parent_inode = (struct ext2_inode *)
+ xzalloc(sizeof(struct ext2_inode));
+ if (!g_parent_inode)
+ goto fail;
+
+ if (ext4fs_init() != 0) {
+ printf("error in File System init\n");
+ return -1;
+ }
+ inodes_per_block = fs->blksz / fs->inodesz;
+ parent_inodeno = get_parent_inode_num(fname, filename, F_FILE);
+ if (parent_inodeno == -1)
+ goto fail;
+ if (iget(parent_inodeno, g_parent_inode))
+ goto fail;
+ /*check if the filename is already present in root */
+ existing_file_inodeno = ext4fs_filename_check(filename);
+ if (existing_file_inodeno != -1) {
+ ret = ext4fs_delete_file(existing_file_inodeno);
+ fs->first_pass_bbmap = 0;
+ fs->curr_blkno = 0;
+
+ fs->first_pass_ibmap = 0;
+ fs->curr_inode_no = 0;
+ if (ret)
+ goto fail;
+ }
+ /*calucalate how many blocks required */
+ total_no_of_bytes_for_file = sizebytes;
+ total_no_of_block_for_file = total_no_of_bytes_for_file / fs->blksz;
+ if (total_no_of_bytes_for_file % fs->blksz != 0) {
+ total_no_of_block_for_file++;
+ debug("total bytes for a file %u\n",
+ total_no_of_block_for_file);
+ }
+ total_remaining_blocks = total_no_of_block_for_file;
+ /*Test for available space in partition */
+ if (fs->sb->free_blocks < total_no_of_block_for_file) {
+ printf("Not enough space on partition !!!\n");
+ goto fail;
+ }
+
+ update_parent_dentry(filename, &inodeno, FILETYPE_REG);
+ /*prepare file inode */
+ inode_buffer = xmalloc(fs->inodesz);
+ memset(inode_buffer, '\0', fs->inodesz);
+ file_inode = (struct ext2_inode *)inode_buffer;
+ file_inode->mode = S_IFREG | S_IRWXU |
+ S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH;
+ /* ToDo: Update correct time */
+ file_inode->mtime = timestamp;
+ file_inode->atime = timestamp;
+ file_inode->ctime = timestamp;
+ file_inode->nlinks = 1;
+ file_inode->size = sizebytes;
+
+ /* Allocate data blocks */
+ allocate_blocks(file_inode, total_remaining_blocks,
+ &total_no_of_block_for_file);
+ /*
+ *write the inode to inode table after last filled inode in inode table
+ *we are using hardcoded gd[0].inode_table_id becuase 0th blockgroup
+ *is suffcient to create more than 1000 file.TODO exapnd the logic to
+ *all blockgroup
+ */
+ file_inode->blockcnt = (total_no_of_block_for_file * fs->blksz)
+ / SECTOR_SIZE;
+
+ temp_ptr = (char *)xzalloc(fs->blksz);
+ if (!temp_ptr)
+ goto fail;
+ inode_bitmap_index = inodeno /
+ (uint32_t) ext4fs_root->sblock.inodes_per_group;
+ inodeno--;
+ itable_blkno =
+ __le32_to_cpu(fs->gd[inode_bitmap_index].inode_table_id) +
+ (inodeno % __le32_to_cpu(sblock->inodes_per_group))
+ / inodes_per_block;
+ blkoff = (inodeno % inodes_per_block) * fs->inodesz;
+ ext2fs_devread(itable_blkno * fs->sect_perblk, 0, fs->blksz, temp_ptr);
+ if (log_journal(temp_ptr, itable_blkno))
+ goto fail;
+
+ memcpy(temp_ptr + blkoff, inode_buffer, fs->inodesz);
+ if (put_metadata(temp_ptr, itable_blkno))
+ goto fail;
+ /*Copy the file content into data blocks */
+ if (ext4fs_write_file(file_inode, 0, sizebytes, (char *)buffer) == -1) {
+ printf("Error in copying content\n");
+ goto fail;
+ }
+ inode_bitmap_index = parent_inodeno /
+ (uint32_t) ext4fs_root->sblock.inodes_per_group;
+ parent_inodeno--;
+ parent_itable_blkno =
+ __le32_to_cpu(fs->gd[inode_bitmap_index].inode_table_id) +
+ (parent_inodeno % __le32_to_cpu(sblock->inodes_per_group)) /
+ inodes_per_block;
+ blkoff = (parent_inodeno % inodes_per_block) * fs->inodesz;
+ if (parent_itable_blkno != itable_blkno) {
+ memset(temp_ptr, '\0', fs->blksz);
+ ext2fs_devread(parent_itable_blkno * fs->sect_perblk,
+ 0, fs->blksz, temp_ptr);
+ if (log_journal(temp_ptr, parent_itable_blkno))
+ goto fail;
+
+ memcpy(temp_ptr + blkoff, g_parent_inode,
+ sizeof(struct ext2_inode));
+ if (put_metadata(temp_ptr, parent_itable_blkno))
+ goto fail;
+ free(temp_ptr);
+ } else {
+ /* If parent and child fall in same inode table block
+ * both should be kept in 1 buffer
+ */
+ memcpy(temp_ptr + blkoff, g_parent_inode,
+ sizeof(struct ext2_inode));
+ gd_index--;
+ if (put_metadata(temp_ptr, itable_blkno))
+ goto fail;
+ free(temp_ptr);
+ }
+ ext4fs_update();
+ ext4fs_deinit();
+
+ fs->first_pass_bbmap = 0;
+ fs->curr_blkno = 0;
+ fs->first_pass_ibmap = 0;
+ fs->curr_inode_no = 0;
+ if (inode_buffer)
+ free(inode_buffer);
+ if (g_parent_inode) {
+ free(g_parent_inode);
+ g_parent_inode = NULL;
+ }
+ return 0;
+
+fail:
+ ext4fs_deinit();
+ if (inode_buffer)
+ free(inode_buffer);
+ if (g_parent_inode) {
+ free(g_parent_inode);
+ g_parent_inode = NULL;
+ }
+ return -1;
+}
diff --git a/include/ext4fs.h b/include/ext4fs.h
index fd7bd47..e4e2c3e 100644
--- a/include/ext4fs.h
+++ b/include/ext4fs.h
@@ -102,9 +102,17 @@ extern block_dev_desc_t *ext4_dev_desc;
extern struct ext2_data *ext4fs_root;
extern struct ext2fs_node *ext4fs_file;
+extern struct ext2_inode *g_parent_inode;
+extern int gd_index;
+extern int gindex;
+
struct ext_filesystem *get_fs(void);
int init_fs(block_dev_desc_t *);
void deinit_fs(block_dev_desc_t *);
+int ext4fs_init(void);
+void ext4fs_deinit(void);
+int ext4fs_write(char *fname, unsigned char *buffer, unsigned long sizebytes);
+int ext4fs_filename_check(char *filename);
int ext4fs_open(const char *filename);
int ext4fs_read(char *buf, unsigned len);
int ext4fs_mount(unsigned part_length);
--
1.7.0.4
5
13
All the global flag defines are the same across all arches (ignoring two
unique x86 ones). So unify them in one place, and add a simple way for
arches to extend for their needs.
Signed-off-by: Mike Frysinger <vapier(a)gentoo.org>
---
note: this depends on Graeme's x86 boot flag clean up
arch/arm/include/asm/global_data.h | 14 +-----------
arch/avr32/include/asm/global_data.h | 14 +-----------
arch/blackfin/include/asm/global_data.h | 14 +-----------
arch/m68k/include/asm/global_data.h | 14 +-----------
arch/microblaze/include/asm/global_data.h | 14 +-----------
arch/mips/include/asm/global_data.h | 14 +-----------
arch/nds32/include/asm/global_data.h | 14 +-----------
arch/nios2/include/asm/global_data.h | 10 +--------
arch/powerpc/include/asm/global_data.h | 14 +-----------
arch/sandbox/include/asm/global_data.h | 14 +-----------
arch/sh/include/asm/global_data.h | 9 +-------
arch/sparc/include/asm/global_data.h | 14 +-----------
arch/x86/include/asm/global_data.h | 16 +-------------
include/asm-generic/global_data_flags.h | 33 +++++++++++++++++++++++++++++
14 files changed, 46 insertions(+), 162 deletions(-)
create mode 100644 include/asm-generic/global_data_flags.h
diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h
index c3ff789..f8088fe 100644
--- a/arch/arm/include/asm/global_data.h
+++ b/arch/arm/include/asm/global_data.h
@@ -29,8 +29,6 @@
* some locked parts of the data cache) to allow for a minimum set of
* global variables during system initialization (until we have set
* up the memory controller so that we can use RAM).
- *
- * Keep it *SMALL* and remember to set GENERATED_GBL_DATA_SIZE > sizeof(gd_t)
*/
typedef struct global_data {
@@ -86,17 +84,7 @@ typedef struct global_data {
#endif
} gd_t;
-/*
- * Global Data Flags
- */
-#define GD_FLG_RELOC 0x00001 /* Code was relocated to RAM */
-#define GD_FLG_DEVINIT 0x00002 /* Devices have been initialized */
-#define GD_FLG_SILENT 0x00004 /* Silent mode */
-#define GD_FLG_POSTFAIL 0x00008 /* Critical POST test failed */
-#define GD_FLG_POSTSTOP 0x00010 /* POST seqeunce aborted */
-#define GD_FLG_LOGINIT 0x00020 /* Log Buffer has been initialized */
-#define GD_FLG_DISABLE_CONSOLE 0x00040 /* Disable console (in & out) */
-#define GD_FLG_ENV_READY 0x00080 /* Environment imported into hash table */
+#include <asm-generic/global_data_flags.h>
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")
diff --git a/arch/avr32/include/asm/global_data.h b/arch/avr32/include/asm/global_data.h
index 5c654bd..7878bb1 100644
--- a/arch/avr32/include/asm/global_data.h
+++ b/arch/avr32/include/asm/global_data.h
@@ -28,8 +28,6 @@
* some locked parts of the data cache) to allow for a minimum set of
* global variables during system initialization (until we have set
* up the memory controller so that we can use RAM).
- *
- * Keep it *SMALL* and remember to set GENERATED_GBL_DATA_SIZE > sizeof(gd_t)
*/
typedef struct global_data {
@@ -52,17 +50,7 @@ typedef struct global_data {
char env_buf[32]; /* buffer for getenv() before reloc. */
} gd_t;
-/*
- * Global Data Flags
- */
-#define GD_FLG_RELOC 0x00001 /* Code was relocated to RAM */
-#define GD_FLG_DEVINIT 0x00002 /* Devices have been initialized */
-#define GD_FLG_SILENT 0x00004 /* Silent mode */
-#define GD_FLG_POSTFAIL 0x00008 /* Critical POST test failed */
-#define GD_FLG_POSTSTOP 0x00010 /* POST seqeunce aborted */
-#define GD_FLG_LOGINIT 0x00020 /* Log Buffer has been initialized */
-#define GD_FLG_DISABLE_CONSOLE 0x00040 /* Disable console (in & out) */
-#define GD_FLG_ENV_READY 0x00080 /* Environment imported into hash table */
+#include <asm-generic/global_data_flags.h>
#define DECLARE_GLOBAL_DATA_PTR register gd_t *gd asm("r5")
diff --git a/arch/blackfin/include/asm/global_data.h b/arch/blackfin/include/asm/global_data.h
index 67aa30f..ad42e91 100644
--- a/arch/blackfin/include/asm/global_data.h
+++ b/arch/blackfin/include/asm/global_data.h
@@ -36,8 +36,6 @@
* some locked parts of the data cache) to allow for a minimum set of
* global variables during system initialization (until we have set
* up the memory controller so that we can use RAM).
- *
- * Keep it *SMALL* and remember to set GENERATED_GBL_DATA_SIZE > sizeof(gd_t)
*/
typedef struct global_data {
bd_t *bd;
@@ -61,17 +59,7 @@ typedef struct global_data {
char env_buf[32]; /* buffer for getenv() before reloc. */
} gd_t;
-/*
- * Global Data Flags
- */
-#define GD_FLG_RELOC 0x00001 /* Code was relocated to RAM */
-#define GD_FLG_DEVINIT 0x00002 /* Devices have been initialized */
-#define GD_FLG_SILENT 0x00004 /* Silent mode */
-#define GD_FLG_POSTFAIL 0x00008 /* Critical POST test failed */
-#define GD_FLG_POSTSTOP 0x00010 /* POST seqeunce aborted */
-#define GD_FLG_LOGINIT 0x00020 /* Log Buffer has been initialized */
-#define GD_FLG_DISABLE_CONSOLE 0x00040 /* Disable console (in & out) */
-#define GD_FLG_ENV_READY 0x00080 /* Environment imported into hash table */
+#include <asm-generic/global_data_flags.h>
#define DECLARE_GLOBAL_DATA_PTR register gd_t * volatile gd asm ("P3")
diff --git a/arch/m68k/include/asm/global_data.h b/arch/m68k/include/asm/global_data.h
index 0ba2b43..cd55b83 100644
--- a/arch/m68k/include/asm/global_data.h
+++ b/arch/m68k/include/asm/global_data.h
@@ -29,8 +29,6 @@
* some locked parts of the data cache) to allow for a minimum set of
* global variables during system initialization (until we have set
* up the memory controller so that we can use RAM).
- *
- * Keep it *SMALL* and remember to set GENERATED_GBL_DATA_SIZE > sizeof(gd_t)
*/
typedef struct global_data {
@@ -70,17 +68,7 @@ typedef struct global_data {
char env_buf[32]; /* buffer for getenv() before reloc. */
} gd_t;
-/*
- * Global Data Flags
- */
-#define GD_FLG_RELOC 0x00001 /* Code was relocated to RAM */
-#define GD_FLG_DEVINIT 0x00002 /* Devices have been initialized */
-#define GD_FLG_SILENT 0x00004 /* Silent mode */
-#define GD_FLG_POSTFAIL 0x00008 /* Critical POST test failed */
-#define GD_FLG_POSTSTOP 0x00010 /* POST seqeunce aborted */
-#define GD_FLG_LOGINIT 0x00020 /* Log Buffer has been initialized */
-#define GD_FLG_DISABLE_CONSOLE 0x00040 /* Disable console (in & out) */
-#define GD_FLG_ENV_READY 0x00080 /* Environment imported into hash table */
+#include <asm-generic/global_data_flags.h>
#if 0
extern gd_t *global_data;
diff --git a/arch/microblaze/include/asm/global_data.h b/arch/microblaze/include/asm/global_data.h
index 6e8537c..0dc4ce9 100644
--- a/arch/microblaze/include/asm/global_data.h
+++ b/arch/microblaze/include/asm/global_data.h
@@ -30,8 +30,6 @@
* some locked parts of the data cache) to allow for a minimum set of
* global variables during system initialization (until we have set
* up the memory controller so that we can use RAM).
- *
- * Keep it *SMALL* and remember to set GENERATED_GBL_DATA_SIZE > sizeof(gd_t)
*/
typedef struct global_data {
@@ -49,17 +47,7 @@ typedef struct global_data {
char env_buf[32]; /* buffer for getenv() before reloc. */
} gd_t;
-/*
- * Global Data Flags
- */
-#define GD_FLG_RELOC 0x00001 /* Code was relocated to RAM */
-#define GD_FLG_DEVINIT 0x00002 /* Devices have been initialized */
-#define GD_FLG_SILENT 0x00004 /* Silent mode */
-#define GD_FLG_POSTFAIL 0x00008 /* Critical POST test failed */
-#define GD_FLG_POSTSTOP 0x00010 /* POST seqeunce aborted */
-#define GD_FLG_LOGINIT 0x00020 /* Log Buffer has been initialized */
-#define GD_FLG_DISABLE_CONSOLE 0x00040 /* Disable console (in & out) */
-#define GD_FLG_ENV_READY 0x00080 /* Environment imported into hash table */
+#include <asm-generic/global_data_flags.h>
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r31")
diff --git a/arch/mips/include/asm/global_data.h b/arch/mips/include/asm/global_data.h
index f6cf9fe..6e2cdc7 100644
--- a/arch/mips/include/asm/global_data.h
+++ b/arch/mips/include/asm/global_data.h
@@ -32,8 +32,6 @@
* some locked parts of the data cache) to allow for a minimum set of
* global variables during system initialization (until we have set
* up the memory controller so that we can use RAM).
- *
- * Keep it *SMALL* and remember to set GENERATED_GBL_DATA_SIZE > sizeof(gd_t)
*/
typedef struct global_data {
@@ -63,17 +61,7 @@ typedef struct global_data {
char env_buf[32]; /* buffer for getenv() before reloc. */
} gd_t;
-/*
- * Global Data Flags
- */
-#define GD_FLG_RELOC 0x00001 /* Code was relocated to RAM */
-#define GD_FLG_DEVINIT 0x00002 /* Devices have been initialized */
-#define GD_FLG_SILENT 0x00004 /* Silent mode */
-#define GD_FLG_POSTFAIL 0x00008 /* Critical POST test failed */
-#define GD_FLG_POSTSTOP 0x00010 /* POST seqeunce aborted */
-#define GD_FLG_LOGINIT 0x00020 /* Log Buffer has been initialized */
-#define GD_FLG_DISABLE_CONSOLE 0x00040 /* Disable console (in & out) */
-#define GD_FLG_ENV_READY 0x00080 /* Environment imported into hash table */
+#include <asm-generic/global_data_flags.h>
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("k0")
diff --git a/arch/nds32/include/asm/global_data.h b/arch/nds32/include/asm/global_data.h
index de20a0a..94bd4c2 100644
--- a/arch/nds32/include/asm/global_data.h
+++ b/arch/nds32/include/asm/global_data.h
@@ -39,8 +39,6 @@
* some locked parts of the data cache) to allow for a minimum set of
* global variables during system initialization (until we have set
* up the memory controller so that we can use RAM).
- *
- * Keep it *SMALL* and remember to set CONFIG_GBL_DATA_SIZE > sizeof(gd_t)
*/
typedef struct global_data {
@@ -67,17 +65,7 @@ typedef struct global_data {
char env_buf[32]; /* buffer for getenv() before reloc. */
} gd_t;
-/*
- * Global Data Flags
- */
-#define GD_FLG_RELOC 0x00001 /* Code was relocated to RAM */
-#define GD_FLG_DEVINIT 0x00002 /* Devices have been initialized */
-#define GD_FLG_SILENT 0x00004 /* Silent mode */
-#define GD_FLG_POSTFAIL 0x00008 /* Critical POST test failed */
-#define GD_FLG_POSTSTOP 0x00010 /* POST seqeunce aborted */
-#define GD_FLG_LOGINIT 0x00020 /* Log Buffer has been initialized */
-#define GD_FLG_DISABLE_CONSOLE 0x00040 /* Disable console (in & out) */
-#define GD_FLG_ENV_READY 0x00080 /* Envs imported into hash table */
+#include <asm-generic/global_data_flags.h>
#ifdef CONFIG_GLOBAL_DATA_NOT_REG10
extern volatile gd_t g_gd;
diff --git a/arch/nios2/include/asm/global_data.h b/arch/nios2/include/asm/global_data.h
index 4b86fbd..3b0d9e6 100644
--- a/arch/nios2/include/asm/global_data.h
+++ b/arch/nios2/include/asm/global_data.h
@@ -44,15 +44,7 @@ typedef struct global_data {
char env_buf[32]; /* buffer for getenv() before reloc. */
} gd_t;
-/* flags */
-#define GD_FLG_RELOC 0x00001 /* Code was relocated to RAM */
-#define GD_FLG_DEVINIT 0x00002 /* Devices have been initialized */
-#define GD_FLG_SILENT 0x00004 /* Silent mode */
-#define GD_FLG_POSTFAIL 0x00008 /* Critical POST test failed */
-#define GD_FLG_POSTSTOP 0x00010 /* POST seqeunce aborted */
-#define GD_FLG_LOGINIT 0x00020 /* Log Buffer has been initialized */
-#define GD_FLG_DISABLE_CONSOLE 0x00040 /* Disable console (in & out) */
-#define GD_FLG_ENV_READY 0x00080 /* Environment imported into hash table */
+#include <asm-generic/global_data_flags.h>
#define DECLARE_GLOBAL_DATA_PTR register gd_t *gd asm ("gp")
diff --git a/arch/powerpc/include/asm/global_data.h b/arch/powerpc/include/asm/global_data.h
index 01f1d4a..5a5877f 100644
--- a/arch/powerpc/include/asm/global_data.h
+++ b/arch/powerpc/include/asm/global_data.h
@@ -33,8 +33,6 @@
* some locked parts of the data cache) to allow for a minimum set of
* global variables during system initialization (until we have set
* up the memory controller so that we can use RAM).
- *
- * Keep it *SMALL* and remember to set GENERATED_GBL_DATA_SIZE > sizeof(gd_t)
*/
typedef struct global_data {
@@ -186,17 +184,7 @@ typedef struct global_data {
char env_buf[32]; /* buffer for getenv() before reloc. */
} gd_t;
-/*
- * Global Data Flags
- */
-#define GD_FLG_RELOC 0x00001 /* Code was relocated to RAM */
-#define GD_FLG_DEVINIT 0x00002 /* Devices have been initialized */
-#define GD_FLG_SILENT 0x00004 /* Silent mode */
-#define GD_FLG_POSTFAIL 0x00008 /* Critical POST test failed */
-#define GD_FLG_POSTSTOP 0x00010 /* POST seqeunce aborted */
-#define GD_FLG_LOGINIT 0x00020 /* Log Buffer has been initialized */
-#define GD_FLG_DISABLE_CONSOLE 0x00040 /* Disable console (in & out) */
-#define GD_FLG_ENV_READY 0x00080 /* Environment imported into hash table */
+#include <asm-generic/global_data_flags.h>
#if 1
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r2")
diff --git a/arch/sandbox/include/asm/global_data.h b/arch/sandbox/include/asm/global_data.h
index 8d47191..64d6ddc 100644
--- a/arch/sandbox/include/asm/global_data.h
+++ b/arch/sandbox/include/asm/global_data.h
@@ -31,8 +31,6 @@
* some locked parts of the data cache) to allow for a minimum set of
* global variables during system initialization (until we have set
* up the memory controller so that we can use RAM).
- *
- * Keep it *SMALL* and remember to set GENERATED_GBL_DATA_SIZE > sizeof(gd_t)
*/
typedef struct global_data {
@@ -49,17 +47,7 @@ typedef struct global_data {
char env_buf[32]; /* buffer for getenv() before reloc. */
} gd_t;
-/*
- * Global Data Flags
- */
-#define GD_FLG_RELOC 0x00001 /* Code was relocated to RAM */
-#define GD_FLG_DEVINIT 0x00002 /* Devices have been initialized */
-#define GD_FLG_SILENT 0x00004 /* Silent mode */
-#define GD_FLG_POSTFAIL 0x00008 /* Critical POST test failed */
-#define GD_FLG_POSTSTOP 0x00010 /* POST seqeunce aborted */
-#define GD_FLG_LOGINIT 0x00020 /* Log Buffer has been initialized */
-#define GD_FLG_DISABLE_CONSOLE 0x00040 /* Disable console (in & out) */
-#define GD_FLG_ENV_READY 0x00080 /* Env. imported into hash table */
+#include <asm-generic/global_data_flags.h>
#define DECLARE_GLOBAL_DATA_PTR extern gd_t *gd
diff --git a/arch/sh/include/asm/global_data.h b/arch/sh/include/asm/global_data.h
index 1b782fc..6e534ad 100644
--- a/arch/sh/include/asm/global_data.h
+++ b/arch/sh/include/asm/global_data.h
@@ -44,14 +44,7 @@ typedef struct global_data
char env_buf[32]; /* buffer for getenv() before reloc. */
} gd_t;
-#define GD_FLG_RELOC 0x00001 /* Code was relocated to RAM */
-#define GD_FLG_DEVINIT 0x00002 /* Devices have been initialized */
-#define GD_FLG_SILENT 0x00004 /* Silent mode */
-#define GD_FLG_POSTFAIL 0x00008 /* Critical POST test failed */
-#define GD_FLG_POSTSTOP 0x00010 /* POST seqeunce aborted */
-#define GD_FLG_LOGINIT 0x00020 /* Log Buffer has been initialized */
-#define GD_FLG_DISABLE_CONSOLE 0x00040 /* Disable console (in & out) */
-#define GD_FLG_ENV_READY 0x00080 /* Environment imported into hash table */
+#include <asm-generic/global_data_flags.h>
#define DECLARE_GLOBAL_DATA_PTR register gd_t *gd asm ("r13")
diff --git a/arch/sparc/include/asm/global_data.h b/arch/sparc/include/asm/global_data.h
index 613e2d8..93d3cc0 100644
--- a/arch/sparc/include/asm/global_data.h
+++ b/arch/sparc/include/asm/global_data.h
@@ -35,8 +35,6 @@
* some locked parts of the data cache) to allow for a minimum set of
* global variables during system initialization (until we have set
* up the memory controller so that we can use RAM).
- *
- * Keep it *SMALL* and remember to set GENERATED_GBL_DATA_SIZE > sizeof(gd_t)
*/
typedef struct global_data {
@@ -78,17 +76,7 @@ typedef struct global_data {
char env_buf[32]; /* buffer for getenv() before reloc. */
} gd_t;
-/*
- * Global Data Flags
- */
-#define GD_FLG_RELOC 0x00001 /* Code was relocated to RAM */
-#define GD_FLG_DEVINIT 0x00002 /* Devices have been initialized */
-#define GD_FLG_SILENT 0x00004 /* Silent mode */
-#define GD_FLG_POSTFAIL 0x00008 /* Critical POST test failed */
-#define GD_FLG_POSTSTOP 0x00010 /* POST seqeunce aborted */
-#define GD_FLG_LOGINIT 0x00020 /* Log Buffer has been initialized */
-#define GD_FLG_DISABLE_CONSOLE 0x00040 /* Disable console (in & out) */
-#define GD_FLG_ENV_READY 0x00080 /* Environment imported into hash table */
+#include <asm-generic/global_data_flags.h>
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("%g7")
diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h
index f177a4f..2b8a2ed 100644
--- a/arch/x86/include/asm/global_data.h
+++ b/arch/x86/include/asm/global_data.h
@@ -29,8 +29,6 @@
* some locked parts of the data cache) to allow for a minimum set of
* global variables during system initialization (until we have set
* up the memory controller so that we can use RAM).
- *
- * Keep it *SMALL* and remember to set GENERATED_GBL_DATA_SIZE > sizeof(gd_t)
*/
#ifndef __ASSEMBLY__
@@ -80,19 +78,7 @@ extern gd_t *gd;
#define GD_SIZE 15
-/*
- * Global Data Flags
- */
-#define GD_FLG_RELOC 0x00001 /* Code was relocated to RAM */
-#define GD_FLG_DEVINIT 0x00002 /* Devices have been initialized */
-#define GD_FLG_SILENT 0x00004 /* Silent mode */
-#define GD_FLG_POSTFAIL 0x00008 /* Critical POST test failed */
-#define GD_FLG_POSTSTOP 0x00010 /* POST seqeunce aborted */
-#define GD_FLG_LOGINIT 0x00020 /* Log Buffer has been initialized */
-#define GD_FLG_DISABLE_CONSOLE 0x00040 /* Disable console (in & out) */
-#define GD_FLG_ENV_READY 0x00080 /* Environment imported into hash table */
-#define GD_FLG_COLD_BOOT 0x00100 /* Cold Boot */
-#define GD_FLG_WARM_BOOT 0x00200 /* Warm Boot */
+#include <asm-generic/global_data_flags.h>
#if 0
#define DECLARE_GLOBAL_DATA_PTR
diff --git a/include/asm-generic/global_data_flags.h b/include/asm-generic/global_data_flags.h
new file mode 100644
index 0000000..ee4ddb7
--- /dev/null
+++ b/include/asm-generic/global_data_flags.h
@@ -0,0 +1,33 @@
+/*
+ * transitional header until we merge global_data.h
+ *
+ * (C) Copyright 2000-2010
+ * Wolfgang Denk, DENX Software Engineering, wd(a)denx.de.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __ASM_GENERIC_GLOBAL_DATA_FLAGS_H
+#define __ASM_GENERIC_GLOBAL_DATA_FLAGS_H
+
+/*
+ * Global Data Flags
+ */
+#define GD_FLG_RELOC 0x00001 /* Code was relocated to RAM */
+#define GD_FLG_DEVINIT 0x00002 /* Devices have been initialized */
+#define GD_FLG_SILENT 0x00004 /* Silent mode */
+#define GD_FLG_POSTFAIL 0x00008 /* Critical POST test failed */
+#define GD_FLG_POSTSTOP 0x00010 /* POST seqeunce aborted */
+#define GD_FLG_LOGINIT 0x00020 /* Log Buffer has been initialized */
+#define GD_FLG_DISABLE_CONSOLE 0x00040 /* Disable console (in & out) */
+#define GD_FLG_ENV_READY 0x00080 /* Environment imported into hash table */
+
+/*
+ * Base for arches to start adding their own:
+ * #define GD_FLG_FOO (GD_FLG_ARCH_BASE << 0)
+ * #define GD_FLG_BAR (GD_FLG_ARCH_BASE << 1)
+ * #define GD_FLG_COW (GD_FLG_ARCH_BASE << 2)
+ */
+#define GD_FLG_ARCH_BASE 0x00100
+
+#endif
--
1.7.6.1
3
11
Hello,
as I am actual trying to get the keymile boards in sync with actual
mainline u-boot, I faced the following Problem with an Intel Strata
Flash on the mgcoge (mpc8247 based board):
I couldn;t unprotect/erase/write/protect some (not all!) Flash sectors.
For Example, I could do this without errors on the sectors where
u-boot sits (First three sectors), but not with the environment (next
two sectors)!
After some debugging, I found out, that, if I revert commit
commit 54652991caedc39b2ec2e5b49e750669bfcd1e2e
Author: Philippe De Muyter <phdm(a)macqel.be>
Date: Tue Aug 17 18:40:25 2010 +0200
Work around bug in Numonyx P33/P30 256-Mbit 65nm flash chips.
I have "ported" U-boot to a in house made board with Numonyx Axcell P33/P30
256-Mbit 65nm flash chips.
After some time :( searching for bugs in our board or soft, we have
discovered that those chips have a small but annoying bug, documented in
"Numonyx Axcell P33/P30 256-Mbit Specification Update"
[...]
It works again fine, and without problems ... did somebody faced
similiar issues with the cfi driver? Some Ideas?
bye,
Heiko
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
5
7

[U-Boot] [PATCH 0/17] tegra: Add display driver and LCD support for Seaboard
by Simon Glass 24 Jul '12
by Simon Glass 24 Jul '12
24 Jul '12
This series adds support for the Tegra2x's display peripheral. This
supports the LCD display on Seaboard and we use this to enable console
output in U-Boot on the LCD.
Configuration is via the device tree. Proposed bindings are included
in this series.
To improve performance two optimisations are offered:
1. The LCD frame buffer is cached, with the cache being flushed after
each call puts(). This dramatically increases performance (around 10x).
This requires a few additions to the ARM cache support.
2. The console supports scrolling in steps of more than 1 line. This
speeds up scrolling output considerably, particularly commands like
'printenv' which display a lot of output. This requires a new CONFIG
and a change to the console_scrollup() function.
Mayuresh Kulkarni (1):
tegra: Enable display/lcd support on Seaboard
Simon Glass (15):
fdt: Add function to look up a phandle's register address
fdt: Add header guard to fdtdec.h
fdt: Correct GPIO name access in fdtdec
tegra: Add display support to funcmux
tegra: fdt: Add LCD definitions for Tegra
tegra: Add support for PWFM
tegra: Add LCD driver
tegra: Add LCD support to Nvidia boards
arm: Add control over cachability of memory regions
lcd: Add CONFIG_ALIGN_LCD_TO_SECTION to align lcd for MMU
lcd: Add support for flushing LCD fb from dcache after update
tegra: Align LCD frame buffer to section boundary
tegra: Support control of cache settings for LCD
tegra: fdt: Add LCD definitions for Seaboard
lcd: Add CONSOLE_SCROLL_LINES option to speed console
Wei Ni (1):
tegra: Add SOC support for display/lcd
README | 16 +
arch/arm/cpu/armv7/cache_v7.c | 11 +
arch/arm/cpu/armv7/tegra2/Makefile | 1 +
arch/arm/cpu/armv7/tegra2/display.c | 271 +++++++++++
arch/arm/cpu/armv7/tegra2/funcmux.c | 39 ++
arch/arm/cpu/armv7/tegra2/pwfm.c | 40 ++
arch/arm/dts/tegra20.dtsi | 25 +
arch/arm/include/asm/arch-tegra2/dc.h | 544 +++++++++++++++++++++++
arch/arm/include/asm/arch-tegra2/display.h | 133 ++++++
arch/arm/include/asm/arch-tegra2/pwfm.h | 54 +++
arch/arm/include/asm/system.h | 30 ++
arch/arm/lib/cache-cp15.c | 62 +++-
board/nvidia/common/board.c | 21 +-
board/nvidia/dts/tegra2-seaboard.dts | 21 +
common/cmd_echo.c | 3 +-
common/lcd.c | 85 +++-
doc/device-tree-bindings/video/nvidia-video.txt | 92 ++++
drivers/video/Makefile | 1 +
drivers/video/tegra.c | 388 ++++++++++++++++
include/configs/seaboard.h | 12 +-
include/configs/tegra2-common.h | 1 +
include/fdtdec.h | 17 +
include/lcd.h | 11 +
lib/fdtdec.c | 15 +-
24 files changed, 1862 insertions(+), 31 deletions(-)
create mode 100644 arch/arm/cpu/armv7/tegra2/display.c
create mode 100644 arch/arm/cpu/armv7/tegra2/pwfm.c
create mode 100644 arch/arm/include/asm/arch-tegra2/dc.h
create mode 100644 arch/arm/include/asm/arch-tegra2/display.h
create mode 100644 arch/arm/include/asm/arch-tegra2/pwfm.h
create mode 100644 doc/device-tree-bindings/video/nvidia-video.txt
create mode 100644 drivers/video/tegra.c
--
1.7.7.3
6
33