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
April 2012
- 163 participants
- 521 discussions
Add support for specifying a differnt CPU for main u-boot and SPL
u-boot builds. This is done by adding an optional SPL CPU after the
main CPU in boards.cfg as follows:
normal_cpu:spl_cpu
This this case CPU will be set to "normal_cpu" during the main u-boot
build and "spl_cpu" during the SPL build.
Signed-off-by: Allen Martin <amartin(a)nvidia.com>
---
This is part of my patch series to move all armv4t code out of tegra
u-boot to an SPL. I haven't heard any suggestions on how to resolve
having a different CPU for the SPL build, so this is my suggestion
as a possible solution.
boards.cfg | 5 +++++
doc/README.SPL | 12 ++++++++++++
mkconfig | 15 ++++++++++++++-
3 files changed, 31 insertions(+), 1 deletions(-)
diff --git a/boards.cfg b/boards.cfg
index 3cf75c3..a58cd02 100644
--- a/boards.cfg
+++ b/boards.cfg
@@ -11,6 +11,11 @@
# Lines starting with '#' are comments.
# Blank lines are ignored.
#
+# The CPU field takes the form:
+# cpu[:spl_cpu]
+# If spl_cpu is specified the make variable CPU will be set to this
+# during the SPL build.
+#
# The options field takes the form:
# <board config name>[:comma separated config options]
# Each config option has the form (value defaults to "1"):
diff --git a/doc/README.SPL b/doc/README.SPL
index 0276953..e4a5ac3 100644
--- a/doc/README.SPL
+++ b/doc/README.SPL
@@ -66,3 +66,15 @@ CONFIG_SPL_DMA_SUPPORT (drivers/dma/libdma.o)
CONFIG_SPL_POST_MEM_SUPPORT (post/drivers/memory.o)
CONFIG_SPL_NAND_LOAD (drivers/mtd/nand/nand_spl_load.o)
CONFIG_SPL_SPI_LOAD (drivers/mtd/spi/spi_spl_load.o)
+
+
+Normally CPU is assumed to be the same between the SPL and normal
+u-boot build. However it is possible to specify a different CPU for
+the SPL build for cases where the SPL is expected to run on a
+different CPU model from the main u-boot. This is done by specifying
+an SPL CPU in boards.cfg as follows:
+
+ normal_cpu:spl_cpu
+
+This this case CPU will be set to "normal_cpu" during the main u-boot
+build and "spl_cpu" during the SPL build.
diff --git a/mkconfig b/mkconfig
index 438530b..82660a6 100755
--- a/mkconfig
+++ b/mkconfig
@@ -60,6 +60,11 @@ CONFIG_NAME="${1%_config}"
arch="$2"
cpu="$3"
+tmp="${cpu#*:}"
+if [ "$tmp" != "$cpu" ] ; then
+ spl_cpu=$tmp
+ cpu="${cpu%:*}"
+fi
if [ "$4" = "-" ] ; then
board=${BOARD_NAME}
else
@@ -131,7 +136,15 @@ fi
# Create include file for Make
#
echo "ARCH = ${arch}" > config.mk
-echo "CPU = ${cpu}" >> config.mk
+if [ ! -z "$spl_cpu" ] ; then
+ echo 'ifeq ($(CONFIG_SPL_BUILD),y)' >> config.mk
+ echo "CPU = ${spl_cpu}" >> config.mk
+ echo "else" >> config.mk
+ echo "CPU = ${cpu}" >> config.mk
+ echo "endif" >> config.mk
+else
+ echo "CPU = ${cpu}" >> config.mk
+fi
echo "BOARD = ${board}" >> config.mk
[ "${vendor}" ] && echo "VENDOR = ${vendor}" >> config.mk
--
1.7.5.4
2
2
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
These are the fixes I needed to do to get my board going.
[PATCH 1/8] i.MX25: add mxc_get_clock infrastructure
SD-controller (fsl_esdhc.c) needs a clock frequency in gd->sdhc_clk. I tried
to follow the idea of other architectures.
[PATCH 2/8] i.MX: Add target flashable to offset 0
Helps flashing with openocd
[PATCH 4/8] i.MX25: Has a GPIO4 too
GPIO4 is used in our board
[PATCH 5/8] MXC FEC: Resolve speed before configuring gasket
Without this 10BaseT doesn't work
First and second OOB bytes are used for bad block indication
USB controller in the i.MX25 has PORTSC register like the controller in i.MX31
BTW, I can't understand what is the meaning of writing into &ehci->control. I
can't find such a register from reference manuals of i.MX25, 28 nor 31.
[PATCH 3/8] Build: Ignore build tree and IDE control file
[PATCH 6/8] i.MX25: Add Exertus EXE4026 board
Maybe these does not belong into this series but I didn't know how to exclude
them from this series.
8
109
Hello,
I have a few sandbox related questions (examples run on v2012.04)
1) Memory map - What is it supposed to look like?
I get "DRAM: 128 MiB", and
=>bdi
boot_params = 0x00000000
DRAM bank = 0x00000000
-> start = 0x00000000
-> size = 0x08000000
FB base = 0x00000000
Yet I get:
=>md 0x100
00000100:Segmentation fault
2) Sandbox does no handle EOF on stadin; this makes it impossible to
use it in test scripts. For example, something like this should
work:
$ echo printenv | ./u-boot
[As woraround I have to use ``echo 'printenv;reset' | ./u-boot'';
this works, but is not really intuitive nore useful.]
3) For automatic test suites it would make a lot of sense if the
return code of U-Boot was the return code of the last executed
command (expecially when termination of U-Boot is the result of
encountering EOF on stdin).
What do you think?
Best regards,
Wolfgang Denk
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd(a)denx.de
There is is no reason for any individual to have a computer in their
home. -- Ken Olsen (President of Digital Equipment Corporation),
Convention of the World Future Society, in Boston, 1977
5
18

[U-Boot] [PATCH v2] powerpc/p1022ds: Add sdcard and spi boot support to P1022DS
by Dirk Eibach 09 Aug '12
by Dirk Eibach 09 Aug '12
09 Aug '12
Signed-off-by: Dirk Eibach <eibach(a)gdsys.de>
Cc: Timur Tabi <timur(a)freescale.com>
---
Changes in v2:
- add Cc
- split up original patch series
board/freescale/p1022ds/p1022ds.c | 4 ++
board/freescale/p1022ds/tlb.c | 10 ++++++
boards.cfg | 4 ++
include/configs/P1022DS.h | 63 ++++++++++++++++++++++++++++++++++---
4 files changed, 76 insertions(+), 5 deletions(-)
diff --git a/board/freescale/p1022ds/p1022ds.c b/board/freescale/p1022ds/p1022ds.c
index 456d9b0..c4bdbad 100644
--- a/board/freescale/p1022ds/p1022ds.c
+++ b/board/freescale/p1022ds/p1022ds.c
@@ -37,6 +37,10 @@ int board_early_init_f(void)
{
ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR;
+ /* Reset eLBC_DIU and SPI_eLBC in case we are booting from SD */
+ clrbits_be32(&gur->pmuxcr, 0x00600000);
+ setbits_be32(&gur->pmuxcr, 0x80000000);
+
/* Set pmuxcr to allow both i2c1 and i2c2 */
setbits_be32(&gur->pmuxcr, 0x1000);
diff --git a/board/freescale/p1022ds/tlb.c b/board/freescale/p1022ds/tlb.c
index e620112..1e9969f 100644
--- a/board/freescale/p1022ds/tlb.c
+++ b/board/freescale/p1022ds/tlb.c
@@ -71,6 +71,16 @@ struct fsl_e_tlb_entry tlb_table[] = {
SET_TLB_ENTRY(1, PIXIS_BASE, PIXIS_BASE_PHYS,
MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,
0, 7, BOOKE_PAGESZ_4K, 1),
+
+#if defined(CONFIG_SYS_RAMBOOT)
+ SET_TLB_ENTRY(1, CONFIG_SYS_DDR_SDRAM_BASE, CONFIG_SYS_DDR_SDRAM_BASE,
+ MAS3_SX|MAS3_SW|MAS3_SR, 0,
+ 0, 8, BOOKE_PAGESZ_1G, 1),
+ SET_TLB_ENTRY(1, CONFIG_SYS_DDR_SDRAM_BASE + 0x40000000,
+ CONFIG_SYS_DDR_SDRAM_BASE + 0x40000000,
+ MAS3_SX|MAS3_SW|MAS3_SR, 0,
+ 0, 9, BOOKE_PAGESZ_1G, 1)
+#endif
};
int num_tlb_entries = ARRAY_SIZE(tlb_table);
diff --git a/boards.cfg b/boards.cfg
index 24c5879..8de4235 100644
--- a/boards.cfg
+++ b/boards.cfg
@@ -700,6 +700,10 @@ P1021RDB-PC_SDCARD powerpc mpc85xx p1_p2_rdb_pc freesca
P1021RDB-PC_SPIFLASH powerpc mpc85xx p1_p2_rdb_pc freescale - p1_p2_rdb_pc:P1021RDB,SPIFLASH
P1022DS powerpc mpc85xx p1022ds freescale
P1022DS_36BIT powerpc mpc85xx p1022ds freescale - P1022DS:36BIT
+P1022DS_36BIT_SDCARD powerpc mpc85xx p1022ds freescale - P1022DS:36BIT,SDCARD
+P1022DS_36BIT_SPIFLASH powerpc mpc85xx p1022ds freescale - P1022DS:36BIT,SPIFLASH
+P1022DS_SDCARD powerpc mpc85xx p1022ds freescale - P1022DS:SDCARD
+P1022DS_SPIFLASH powerpc mpc85xx p1022ds freescale - P1022DS:SPIFLASH
P1023RDS powerpc mpc85xx p1023rds freescale - P1023RDS
P1023RDS_NAND powerpc mpc85xx p1023rds freescale - P1023RDS:NAND
P1024RDB powerpc mpc85xx p1_p2_rdb_pc freescale - p1_p2_rdb_pc:P1024RDB
diff --git a/include/configs/P1022DS.h b/include/configs/P1022DS.h
index 70d751d..73a56a6 100644
--- a/include/configs/P1022DS.h
+++ b/include/configs/P1022DS.h
@@ -26,6 +26,18 @@
#define CONFIG_P1022DS
#define CONFIG_MP /* support multiple processors */
+#ifdef CONFIG_SDCARD
+#define CONFIG_RAMBOOT_SDCARD 1
+#define CONFIG_SYS_TEXT_BASE 0x11000000
+#define CONFIG_RESET_VECTOR_ADDRESS 0x1107fffc
+#endif
+
+#ifdef CONFIG_SPIFLASH
+#define CONFIG_RAMBOOT_SPIFLASH 1
+#define CONFIG_SYS_TEXT_BASE 0x11000000
+#define CONFIG_RESET_VECTOR_ADDRESS 0x1107fffc
+#endif
+
#ifndef CONFIG_SYS_TEXT_BASE
#define CONFIG_SYS_TEXT_BASE 0xeff80000
#endif
@@ -52,8 +64,14 @@
#define CONFIG_FSL_LAW /* Use common FSL init code */
+#if 0
+#define CONFIG_SYS_CLK_FREQ 99999000 /* get_board_sys_clk() */
+#define CONFIG_DDR_CLK_FREQ 99999000 /* get_board_ddr_clk() */
+#else
#define CONFIG_SYS_CLK_FREQ get_board_sys_clk()
#define CONFIG_DDR_CLK_FREQ get_board_ddr_clk()
+#endif
+
#define CONFIG_ICS307_REFCLK_HZ 33333000 /* ICS307 clock chip ref freq */
/*
@@ -138,6 +156,14 @@
#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE /* start of monitor */
+#if defined(CONFIG_RAMBOOT_NAND) || defined(CONFIG_RAMBOOT_SDCARD) || \
+ defined(CONFIG_RAMBOOT_SPIFLASH)
+#define CONFIG_SYS_RAMBOOT
+#define CONFIG_SYS_EXTRA_ENV_RELOC
+#else
+#undef CONFIG_SYS_RAMBOOT
+#endif
+
#define CONFIG_FLASH_CFI_DRIVER
#define CONFIG_SYS_FLASH_CFI
#define CONFIG_SYS_FLASH_EMPTY_INFO
@@ -403,11 +429,38 @@
/*
* Environment
*/
-#define CONFIG_ENV_IS_IN_FLASH
-#define CONFIG_ENV_OVERWRITE
-#define CONFIG_ENV_ADDR (CONFIG_SYS_MONITOR_BASE - CONFIG_ENV_SECT_SIZE)
-#define CONFIG_ENV_SIZE 0x2000
-#define CONFIG_ENV_SECT_SIZE 0x20000
+#if defined(CONFIG_SYS_RAMBOOT)
+#if defined(CONFIG_RAMBOOT_NAND)
+#define CONFIG_ENV_IS_IN_NAND 1
+#define CONFIG_ENV_SIZE CONFIG_SYS_NAND_BLOCK_SIZE
+#define CONFIG_ENV_OFFSET ((512 * 1024) + CONFIG_SYS_NAND_BLOCK_SIZE)
+#define CONFIG_ENV_RANGE (3 * CONFIG_ENV_SIZE)
+#elif defined(CONFIG_RAMBOOT_SPIFLASH)
+#define CONFIG_ENV_IS_IN_SPI_FLASH
+#define CONFIG_ENV_SPI_BUS 0
+#define CONFIG_ENV_SPI_CS 0
+#define CONFIG_ENV_SPI_MAX_HZ 10000000
+#define CONFIG_ENV_SPI_MODE 0
+#define CONFIG_ENV_SIZE 0x2000 /* 8KB */
+#define CONFIG_ENV_OFFSET 0x100000
+#define CONFIG_ENV_SECT_SIZE 0x10000
+#elif defined(CONFIG_RAMBOOT_SDCARD)
+#define CONFIG_ENV_IS_IN_MMC
+#define CONFIG_FSL_FIXED_MMC_LOCATION
+#define CONFIG_ENV_SIZE 0x2000
+#define CONFIG_SYS_MMC_ENV_DEV 0
+#else
+ #define CONFIG_ENV_IS_NOWHERE 1 /* Store ENV in memory only */
+ #define CONFIG_ENV_ADDR (CONFIG_SYS_MONITOR_BASE - 0x1000)
+ #define CONFIG_ENV_SIZE 0x2000
+#endif
+#else
+ #define CONFIG_ENV_IS_IN_FLASH
+ #define CONFIG_ENV_OVERWRITE
+ #define CONFIG_ENV_ADDR (CONFIG_SYS_MONITOR_BASE - CONFIG_ENV_SECT_SIZE)
+ #define CONFIG_ENV_SIZE 0x2000
+ #define CONFIG_ENV_SECT_SIZE 0x20000
+#endif
#define CONFIG_LOADS_ECHO
#define CONFIG_SYS_LOADS_BAUD_CHANGE
--
1.7.2.5
3
3
Signed-off-by: Eric Nelson <eric.nelson(a)boundarydevices.com>
---
doc/README.kbd | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 84 insertions(+), 0 deletions(-)
create mode 100644 doc/README.kbd
diff --git a/doc/README.kbd b/doc/README.kbd
new file mode 100644
index 0000000..dff4b92
--- /dev/null
+++ b/doc/README.kbd
@@ -0,0 +1,84 @@
+Keyboard handling
+========================================
+This document describes asynchronous keyboard handling, also
+known as "magic key" or "button" handling used to alter the
+boot flow at power-on when one or more keys or buttons are
+pressed.
+
+Note that "keyboard" has multiple meanings, and this document
+does not describe the use of keyboards as a tty or console
+input device.
+
+Think of the button on your WiFi access point that resets to
+factory defaults and not the keyboard on your desk.
+
+This use case is similar in function to the mechanism used
+by a PC BIOS to enter a setup application at boot time or
+on an Android device to access "recovery" mode.
+
+At the highest level, the function of this subsystem is to
+run a set of commands other than the content of the "bootcmd"
+environment variable when one or more keys is pressed at
+startup. The alternate commands are also stored in environment
+variables as illustrated in this snippet from the file
+include/configs/lwmon.h:
+
+"key_cmd2=echo *** Entering Update Mode ***;" \
+ "if fatload ide 0:3 10000 update.scr;" \
+ "then source 10000;" \
+ "else echo *** UPDATE FAILED ***;" \
+ "fi\0" \
+
+As of this writing, there are eight boards which implement
+this mechanism:
+ enbw/enbw_cmc/enbw_cmc.c
+ lwmon/lwmon.c
+ lwmon5/kbd.c
+ manroland/hmi1001/hmi1001.c
+ manroland/uc101/uc101.c
+ manroland/mucmc52/mucmc52.c
+ pcs440ep/pcs440ep.c
+ r360mpi/r360mpi.c
+
+They all share some things in common:
+
+1. They each check for keys pressed in misc_init_r() and
+ use the content of the environment variable "magic_keys"
+ to locate command strings matching key combinations.
+2. If a keystroke is matched, it is placed into the "preboot"
+ environment variable.
+3. The "magic_keys" environment variable is used as an
+ index or pointer of sorts to other environment variables
+ which contain key combinations.
+4. Each character in the value of "magic_keys" is used as a
+ suffix for a key-combination environment variable name.
+ The name "key_magic" is used in all implementations except
+ enbw_cmc.
+ For example, if "magic_keys" contains the value "1234",
+ the code will check against these environment variables.
+ key_magic1
+ key_magic2
+ key_magic3
+ key_magic4
+5. If the currently pressed key combination matches the
+ content of the key_magicX variable, the content of
+ another variable, "key_cmdX" is copied to "preboot".
+
+The implementations otherwise vary.
+
+Some implementations, notably the lwmon and r360mpi boards,
+include a command "kbd", which is used to read the current
+key state into an environment variable "keybd".
+
+To recap: to implement this for your platform, you should do the
+following.
+
+Add a section conditional on CONFIG_PREBOOT to implement the
+key handling:
+
+ #ifdef CONFIG_PREBOOT
+ #endif
+
+If CONFIG_PREBOOT is set, add a call to check and conditionally
+define the "preboot" variable based on the current key state.
+
--
1.7.9
3
5

09 Aug '12
CONFIG_DISCOVER_PHY is not used anywhere, so remove it from config files.
Signed-off-by: Fabio Estevam <fabio.estevam(a)freescale.com>
---
include/configs/flea3.h | 1 -
include/configs/m28evk.h | 1 -
include/configs/mx28evk.h | 1 -
include/configs/mx35pdk.h | 1 -
include/configs/mx51evk.h | 1 -
include/configs/mx53ard.h | 1 -
include/configs/mx53evk.h | 1 -
include/configs/mx53loco.h | 1 -
include/configs/mx53smd.h | 1 -
include/configs/vision2.h | 1 -
10 files changed, 0 insertions(+), 10 deletions(-)
diff --git a/include/configs/flea3.h b/include/configs/flea3.h
index f046a58..62c69c1 100644
--- a/include/configs/flea3.h
+++ b/include/configs/flea3.h
@@ -122,7 +122,6 @@
#define CONFIG_FEC_MXC_PHYADDR 0x1
#define CONFIG_MII
-#define CONFIG_DISCOVER_PHY
#define CONFIG_ARP_TIMEOUT 200UL
diff --git a/include/configs/m28evk.h b/include/configs/m28evk.h
index 4df013c..c8943d3 100644
--- a/include/configs/m28evk.h
+++ b/include/configs/m28evk.h
@@ -192,7 +192,6 @@
#define CONFIG_FEC_MXC
#define CONFIG_FEC_MXC_MULTI
#define CONFIG_MII
-#define CONFIG_DISCOVER_PHY
#define CONFIG_FEC_XCV_TYPE RMII
#endif
diff --git a/include/configs/mx28evk.h b/include/configs/mx28evk.h
index 02f3366..2c2e3b3 100644
--- a/include/configs/mx28evk.h
+++ b/include/configs/mx28evk.h
@@ -156,7 +156,6 @@
#define CONFIG_FEC_MXC
#define CONFIG_FEC_MXC_MULTI
#define CONFIG_MII
-#define CONFIG_DISCOVER_PHY
#define CONFIG_FEC_XCV_TYPE RMII
#define CONFIG_MX28_FEC_MAC_IN_OCOTP
#endif
diff --git a/include/configs/mx35pdk.h b/include/configs/mx35pdk.h
index 1e03639..94362ab 100644
--- a/include/configs/mx35pdk.h
+++ b/include/configs/mx35pdk.h
@@ -138,7 +138,6 @@
#define CONFIG_FEC_MXC_PHYADDR 0x1F
#define CONFIG_MII
-#define CONFIG_DISCOVER_PHY
#define CONFIG_ARP_TIMEOUT 200UL
diff --git a/include/configs/mx51evk.h b/include/configs/mx51evk.h
index 1477b21..9c6b2ac 100644
--- a/include/configs/mx51evk.h
+++ b/include/configs/mx51evk.h
@@ -99,7 +99,6 @@
*/
#define CONFIG_HAS_ETH1
#define CONFIG_MII
-#define CONFIG_DISCOVER_PHY
#define CONFIG_FEC_MXC
#define IMX_FEC_BASE FEC_BASE_ADDR
diff --git a/include/configs/mx53ard.h b/include/configs/mx53ard.h
index f48a41e..d369e37 100644
--- a/include/configs/mx53ard.h
+++ b/include/configs/mx53ard.h
@@ -69,7 +69,6 @@
#define CONFIG_HAS_ETH1
#define CONFIG_MII
#define CONFIG_MII_GASKET
-#define CONFIG_DISCOVER_PHY
#define CONFIG_CMD_PING
#define CONFIG_CMD_DHCP
diff --git a/include/configs/mx53evk.h b/include/configs/mx53evk.h
index a77e5b2..7346611 100644
--- a/include/configs/mx53evk.h
+++ b/include/configs/mx53evk.h
@@ -78,7 +78,6 @@
/* Eth Configs */
#define CONFIG_HAS_ETH1
#define CONFIG_MII
-#define CONFIG_DISCOVER_PHY
#define CONFIG_FEC_MXC
#define IMX_FEC_BASE FEC_BASE_ADDR
diff --git a/include/configs/mx53loco.h b/include/configs/mx53loco.h
index 34a4edd..34053ba 100644
--- a/include/configs/mx53loco.h
+++ b/include/configs/mx53loco.h
@@ -61,7 +61,6 @@
/* Eth Configs */
#define CONFIG_HAS_ETH1
#define CONFIG_MII
-#define CONFIG_DISCOVER_PHY
#define CONFIG_FEC_MXC
#define IMX_FEC_BASE FEC_BASE_ADDR
diff --git a/include/configs/mx53smd.h b/include/configs/mx53smd.h
index a04db3f..f432cfd 100644
--- a/include/configs/mx53smd.h
+++ b/include/configs/mx53smd.h
@@ -68,7 +68,6 @@
/* Eth Configs */
#define CONFIG_HAS_ETH1
#define CONFIG_MII
-#define CONFIG_DISCOVER_PHY
#define CONFIG_FEC_MXC
#define IMX_FEC_BASE FEC_BASE_ADDR
diff --git a/include/configs/vision2.h b/include/configs/vision2.h
index f6904f3..ae6a86e 100644
--- a/include/configs/vision2.h
+++ b/include/configs/vision2.h
@@ -122,7 +122,6 @@
*/
#define CONFIG_HAS_ETH1
#define CONFIG_MII
-#define CONFIG_DISCOVER_PHY
#define CONFIG_FEC_MXC
#define IMX_FEC_BASE FEC_BASE_ADDR
--
1.7.1
2
1

[U-Boot] [PATCH] powerpc:Fix return type & parameter passed for I/O functions
by Prabhakar Kushwaha 09 Aug '12
by Prabhakar Kushwaha 09 Aug '12
09 Aug '12
Return type of in_8, in_be16 and in_le16 should not be'int'. Update it to type
u8/u16/u32.
Although 'unsigned' for in_be32 and in_le32 is correct. But to make return type
uniform across the file changed to u32
Similarly, parameter passed to out_8, out_be16, out_le16 ,out_be32 & out_le32
should not be 'int'.Change it to type u8/u16/u32.
Signed-off-by: Prabhakar Kushwaha <prabhakar(a)freescale.com>
---
Based upon git://git.denx.de/u-boot.git branch master
arch/powerpc/include/asm/io.h | 30 +++++++++++++++---------------
1 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h
index 56ac9fe..0a71bb9 100644
--- a/arch/powerpc/include/asm/io.h
+++ b/arch/powerpc/include/asm/io.h
@@ -162,9 +162,9 @@ static inline void __raw_writel(unsigned int v, volatile void __iomem *addr)
* is actually performed (i.e. the data has come back) before we start
* executing any following instructions.
*/
-extern inline int in_8(const volatile unsigned char __iomem *addr)
+extern inline u8 in_8(const volatile unsigned char __iomem *addr)
{
- int ret;
+ u8 ret;
__asm__ __volatile__(
"sync; lbz%U1%X1 %0,%1;\n"
@@ -173,7 +173,7 @@ extern inline int in_8(const volatile unsigned char __iomem *addr)
return ret;
}
-extern inline void out_8(volatile unsigned char __iomem *addr, int val)
+extern inline void out_8(volatile unsigned char __iomem *addr, u8 val)
{
__asm__ __volatile__("sync;\n"
"stb%U0%X0 %1,%0;\n"
@@ -181,9 +181,9 @@ extern inline void out_8(volatile unsigned char __iomem *addr, int val)
: "r" (val));
}
-extern inline int in_le16(const volatile unsigned short __iomem *addr)
+extern inline u16 in_le16(const volatile unsigned short __iomem *addr)
{
- int ret;
+ u16 ret;
__asm__ __volatile__("sync; lhbrx %0,0,%1;\n"
"twi 0,%0,0;\n"
@@ -192,9 +192,9 @@ extern inline int in_le16(const volatile unsigned short __iomem *addr)
return ret;
}
-extern inline int in_be16(const volatile unsigned short __iomem *addr)
+extern inline u16 in_be16(const volatile unsigned short __iomem *addr)
{
- int ret;
+ u16 ret;
__asm__ __volatile__("sync; lhz%U1%X1 %0,%1;\n"
"twi 0,%0,0;\n"
@@ -202,20 +202,20 @@ extern inline int in_be16(const volatile unsigned short __iomem *addr)
return ret;
}
-extern inline void out_le16(volatile unsigned short __iomem *addr, int val)
+extern inline void out_le16(volatile unsigned short __iomem *addr, u16 val)
{
__asm__ __volatile__("sync; sthbrx %1,0,%2" : "=m" (*addr) :
"r" (val), "r" (addr));
}
-extern inline void out_be16(volatile unsigned short __iomem *addr, int val)
+extern inline void out_be16(volatile unsigned short __iomem *addr, u16 val)
{
__asm__ __volatile__("sync; sth%U0%X0 %1,%0" : "=m" (*addr) : "r" (val));
}
-extern inline unsigned in_le32(const volatile unsigned __iomem *addr)
+extern inline u32 in_le32(const volatile unsigned __iomem *addr)
{
- unsigned ret;
+ u32 ret;
__asm__ __volatile__("sync; lwbrx %0,0,%1;\n"
"twi 0,%0,0;\n"
@@ -224,9 +224,9 @@ extern inline unsigned in_le32(const volatile unsigned __iomem *addr)
return ret;
}
-extern inline unsigned in_be32(const volatile unsigned __iomem *addr)
+extern inline u32 in_be32(const volatile unsigned __iomem *addr)
{
- unsigned ret;
+ u32 ret;
__asm__ __volatile__("sync; lwz%U1%X1 %0,%1;\n"
"twi 0,%0,0;\n"
@@ -234,13 +234,13 @@ extern inline unsigned in_be32(const volatile unsigned __iomem *addr)
return ret;
}
-extern inline void out_le32(volatile unsigned __iomem *addr, int val)
+extern inline void out_le32(volatile unsigned __iomem *addr, u32 val)
{
__asm__ __volatile__("sync; stwbrx %1,0,%2" : "=m" (*addr) :
"r" (val), "r" (addr));
}
-extern inline void out_be32(volatile unsigned __iomem *addr, int val)
+extern inline void out_be32(volatile unsigned __iomem *addr, u32 val)
{
__asm__ __volatile__("sync; stw%U0%X0 %1,%0" : "=m" (*addr) : "r" (val));
}
--
1.7.5.4
2
1

[U-Boot] [PATCH] UBIFS: Improve error message when reading superblock failed
by Bernhard Walle 09 Aug '12
by Bernhard Walle 09 Aug '12
09 Aug '12
In addition to the error message also display the error code. I had the
problem that my malloc memory was not enough (ENOMEM), and if u-boot
had displayed the error code immediately that would have saved me some
debugging.
Signed-off-by: Bernhard Walle <walle(a)corscience.de>
---
fs/ubifs/super.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 26b48f0..0b1440b 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -1191,7 +1191,7 @@ int ubifs_mount(char *vol_name)
mnt = NULL;
ret = ubifs_get_sb(&ubifs_fs_type, flags, name, data, mnt);
if (ret) {
- printf("Error reading superblock on volume '%s'!\n", name);
+ printf("Error reading superblock on volume '%s': %d!\n", name, -ret);
return -1;
}
--
1.7.9
6
10

09 Aug '12
This new function runs a list of commands separated by semicolon or newline.
We move this out of cmd_source so that it can be used by other code. The
PXE code also uses the new function.
Suggested-by: Michael Walle <michael(a)walle.cc>
Signed-off-by: Simon Glass <sjg(a)chromium.org>
---
Changes in v3:
- Added a few more comments on the need for malloc()
- Change PXE's printf() to a debug()
- Fix bug in built-in run_command()
- Fix commit message to mention ; and \n
- Move run_command_list() comment to header file
common/cmd_pxe.c | 20 ++----------
common/cmd_source.c | 49 +----------------------------
common/main.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++
include/common.h | 13 ++++++++
4 files changed, 102 insertions(+), 65 deletions(-)
diff --git a/common/cmd_pxe.c b/common/cmd_pxe.c
index b3c1f67..6032a0f 100644
--- a/common/cmd_pxe.c
+++ b/common/cmd_pxe.c
@@ -515,33 +515,19 @@ static void label_print(void *data)
*/
static int label_localboot(struct pxe_label *label)
{
- char *localcmd, *dupcmd;
- int ret;
+ char *localcmd;
localcmd = from_env("localcmd");
if (!localcmd)
return -ENOENT;
- /*
- * dup the command to avoid any issues with the version of it existing
- * in the environment changing during the execution of the command.
- */
- dupcmd = strdup(localcmd);
-
- if (!dupcmd)
- return -ENOMEM;
-
if (label->append)
setenv("bootargs", label->append);
- printf("running: %s\n", dupcmd);
-
- ret = run_command(dupcmd, 0);
+ debug("running: %s\n", localcmd);
- free(dupcmd);
-
- return ret;
+ return run_command_list(localcmd, strlen(localcmd), 0);
}
/*
diff --git a/common/cmd_source.c b/common/cmd_source.c
index 32fff5c..c4cde98 100644
--- a/common/cmd_source.c
+++ b/common/cmd_source.c
@@ -39,9 +39,6 @@
#if defined(CONFIG_8xx)
#include <mpc8xx.h>
#endif
-#ifdef CONFIG_SYS_HUSH_PARSER
-#include <hush.h>
-#endif
int
source (ulong addr, const char *fit_uname)
@@ -49,8 +46,6 @@ source (ulong addr, const char *fit_uname)
ulong len;
image_header_t *hdr;
ulong *data;
- char *cmd;
- int rcode = 0;
int verify;
#if defined(CONFIG_FIT)
const void* fit_hdr;
@@ -151,49 +146,7 @@ source (ulong addr, const char *fit_uname)
}
debug ("** Script length: %ld\n", len);
-
- if ((cmd = malloc (len + 1)) == NULL) {
- return 1;
- }
-
- /* make sure cmd is null terminated */
- memmove (cmd, (char *)data, len);
- *(cmd + len) = 0;
-
-#ifdef CONFIG_SYS_HUSH_PARSER /*?? */
- rcode = parse_string_outer (cmd, FLAG_PARSE_SEMICOLON);
-#else
- {
- char *line = cmd;
- char *next = cmd;
-
- /*
- * break into individual lines,
- * and execute each line;
- * terminate on error.
- */
- while (*next) {
- if (*next == '\n') {
- *next = '\0';
- /* run only non-empty commands */
- if (*line) {
- debug ("** exec: \"%s\"\n",
- line);
- if (run_command(line, 0) < 0) {
- rcode = 1;
- break;
- }
- }
- line = next + 1;
- }
- ++next;
- }
- if (rcode == 0 && *line)
- rcode = (run_command(line, 0) >= 0);
- }
-#endif
- free (cmd);
- return rcode;
+ return run_command_list((char *)data, len, 0);
}
/**************************************************/
diff --git a/common/main.c b/common/main.c
index db181d3..8c5115d 100644
--- a/common/main.c
+++ b/common/main.c
@@ -30,6 +30,7 @@
#include <common.h>
#include <watchdog.h>
#include <command.h>
+#include <malloc.h>
#include <version.h>
#ifdef CONFIG_MODEM_SUPPORT
#include <malloc.h> /* for free() prototype */
@@ -1373,6 +1374,90 @@ int run_command(const char *cmd, int flag)
#endif
}
+#ifndef CONFIG_SYS_HUSH_PARSER
+/**
+ * Execute a list of command separated by ; or \n using the built-in parser.
+ *
+ * This function cannot take a const char * for the command, since if it
+ * finds newlines in the string, it replaces them with \0.
+ *
+ * @param cmd String containing list of commands
+ * @param flag Execution flags (CMD_FLAG_...)
+ * @return 0 on success, or != 0 on error.
+ */
+static int builtin_run_command_list(char *cmd, int flag)
+{
+ char *line, *next;
+ int rcode = 0;
+
+ /*
+ * Break into individual lines, and execute each line; terminate on
+ * error.
+ */
+ line = next = cmd;
+ while (*next) {
+ if (*next == '\n') {
+ *next = '\0';
+ /* run only non-empty commands */
+ if (*line) {
+ debug("** exec: \"%s\"\n", line);
+ if (builtin_run_command(line, 0) < 0) {
+ rcode = 1;
+ break;
+ }
+ }
+ line = next + 1;
+ }
+ ++next;
+ }
+ if (rcode == 0 && *line)
+ rcode = (builtin_run_command(line, 0) >= 0);
+
+ return rcode;
+}
+#endif
+
+int run_command_list(const char *cmd, int len, int flag)
+{
+ int need_buff = 1;
+ char *buff = (char *)cmd; /* cast away const */
+ int rcode = 0;
+
+ if (len == -1) {
+ len = strlen(cmd);
+#ifdef CONFIG_SYS_HUSH_PARSER
+ /* hush will never change our string */
+ need_buff = 0;
+#else
+ /* the built-in parser will change our string if it sees \n */
+ need_buff = strchr(cmd, '\n') != NULL;
+#endif
+ }
+ if (need_buff) {
+ buff = malloc(len + 1);
+ if (!buff)
+ return 1;
+ memcpy(buff, cmd, len);
+ buff[len] = '\0';
+ }
+#ifdef CONFIG_SYS_HUSH_PARSER
+ rcode = parse_string_outer(buff, FLAG_PARSE_SEMICOLON);
+#else
+ /*
+ * This function will overwrite any \n it sees with a \0, which
+ * is why it can't work with a const char *. Here we are making
+ * using of internal knowledge of this function, to avoid always
+ * doing a malloc() which is actually required only in a case that
+ * is pretty rare.
+ */
+ rcode = builtin_run_command_list(buff, flag);
+ if (need_buff)
+ free(buff);
+#endif
+
+ return rcode;
+}
+
/****************************************************************************/
#if defined(CONFIG_CMD_RUN)
diff --git a/include/common.h b/include/common.h
index 74d9704..c4ae451 100644
--- a/include/common.h
+++ b/include/common.h
@@ -268,6 +268,19 @@ int print_buffer (ulong addr, void* data, uint width, uint count, uint linelen);
/* common/main.c */
void main_loop (void);
int run_command(const char *cmd, int flag);
+
+/**
+ * Run a list of commands separated by ; or even \0
+ *
+ * Note that if 'len' is not -1, then the command does not need to be nul
+ * terminated, Memory will be allocated for the command in that case.
+ *
+ * @param cmd List of commands to run, each separated bu semicolon
+ * @param len Length of commands excluding terminator if known (-1 if not)
+ * @param flag Execution flags (CMD_FLAG_...)
+ * @return 0 on success, or != 0 on error.
+ */
+int run_command_list(const char *cmd, int len, int flag);
int readline (const char *const prompt);
int readline_into_buffer(const char *const prompt, char *buffer,
int timeout);
--
1.7.7.3
3
15