All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 2/2] ext4fs write support
@ 2011-12-15 17:39 uma.shankar at samsung.com
  2011-12-15 22:20 ` Kim Phillips
                   ` (2 more replies)
  0 siblings, 3 replies; 14+ messages in thread
From: uma.shankar at samsung.com @ 2011-12-15 17:39 UTC (permalink / raw)
  To: u-boot

From: Uma Shankar <uma.shankar@samsung.com>

Signed-off-by: Uma Shankar <uma.shankar@samsung.com>
Signed-off-by: Manjunatha C Achar <a.manjunatha@samsung.com>
Signed-off-by: Iqbal Shareef <iqbal.ams@samsung.com>
Signed-off-by: Hakgoo Lee <goodguy.lee@samsung.com>
---
 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@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@samsung.com>
+ * Manjunatha C Achar <a.manjunatha@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@samsung.com>
+ * Manjunatha C Achar <a.manjunatha@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

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [U-Boot] [PATCH 2/2] ext4fs write support
  2011-12-15 17:39 [U-Boot] [PATCH 2/2] ext4fs write support uma.shankar at samsung.com
@ 2011-12-15 22:20 ` Kim Phillips
  2011-12-16 16:10 ` Mike Frysinger
  2011-12-28  2:23 ` [U-Boot] [PATCH V3 " uma.shankar at samsung.com
  2 siblings, 0 replies; 14+ messages in thread
From: Kim Phillips @ 2011-12-15 22:20 UTC (permalink / raw)
  To: u-boot

On Thu, 15 Dec 2011 23:09:53 +0530
<uma.shankar@samsung.com> wrote:

>  fs/ext4/crc16.c        |   62 +++
>  fs/ext4/crc16.h        |   16 +

there are already three crc16 implementations in u-boot according to
my count.  Please let's not add a fourth - hopefully the only thing
wrong with using lib/crc16.c was that you weren't aware it existed.

> +	/*get the filename */

> +	/*get the address in hexadecimal format (string to int) */

> +	/*get the filesize in base 10 format */

> +	/*set the device as block device */

> +	/*register the device and partition */

> +	/*get the partition information */

> +	/*mount the filesystem */

> +	/*start write */

space after the /*

> +	if (status)
> +		*ptr = *ptr & ~(operand);
> +	return;

> +	}
> +	return crc;

insert blank line before return statements

> +static int check_void_in_dentry(struct ext2_dirent *dir, char *filename)

> +	dentry_length = sizeof(struct ext2_dirent) +
> +	    dir->namelen + padding_factor;

alignment

> +	sizeof_void_space = dir->direntlen - dentry_length;
> +	if (sizeof_void_space == 0) {
> +		return 0;
> +	} else {
> +		padding_factor = 0;

if (sizeof_void_space == 0)
	return 0;

padding_factor = 0;
...

> +		new_entry_byte_reqd = strlen(filename) +
> +		    sizeof(struct ext2_dirent) + padding_factor;

alignment

> +		if (sizeof_void_space >= new_entry_byte_reqd) {
> +			dir->direntlen = dentry_length;
> +			return sizeof_void_space;
> +		} else
> +			return 0;

if (sizeof_void_space >= new_entry_byte_reqd) {
	dir->direntlen = dentry_length;
	return sizeof_void_space;
}

return 0;

> +	/*##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*/

/*
 * multi-line comments
 * are formatted
 * like this
 */


> +	zero_buffer = xzalloc(fs->blksz);
> +	if (!zero_buffer)
> +		return;

> +	root_first_block_buffer = (char *)xzalloc(fs->blksz);
> +	if (!root_first_block_buffer)
> +		return;

first time reviewing fs code, can this fn be modified to return an
error code?  If not, at least print something.

> +RESTART:

labels in lowercase

> +	status = ext2fs_devread(first_block_no_of_root
> +				* fs->sect_perblk,

operator at end of prior line

> +				0, fs->blksz, root_first_block_buffer);
> +	if (status == 0)
> +		goto fail;
> +	else {
> +		if (log_journal(root_first_block_buffer,

if (...)
	goto fail;

if (log_journal(...

this will save horizontal space for some tightly right-justified
code under it.

> +				last_entry_dirlen = dir->namelen +
> +				    sizeof(struct ext2_dirent) + padding_factor;

alignment

> +				if ((fs->blksz - totalbytes - last_entry_dirlen)
> +				    < new_entry_byte_reqd) {

operator on prior line

> +					printf("1st Block Full:"
> +					"allocating new block\n");

here,

> +					if (direct_blk_idx ==
> +					    INDIRECT_BLOCKS - 1) {
> +						printf("Directory capacity"
> +						"exceeds the limit\n");

here,

> +						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");

and here, this prevents users trying to grep for this error text - I believe
it's allowed to exceed 80 columns in this case.

> +	/*END: Update the root directory entry block of root inode */

is some tool you're using supposed to correlate this with the above?:

/*##START: Update the root directory entry block of root inode ### */

If so, we (or certainly I) don't use it, and therefore don't care
for it - please remove it, and any other instances.

> +	/*get the first block of root */
> +	/*read the block no allocated to a file */

fix comment format

> +		status = ext2fs_devread(blknr * fs->sect_perblk,
> +					0, fs->blksz, (char *)block_buffer);
> +		if (status == 0)
> +			goto fail;
> +		else {

again, rm the else to avoid unnecessary indentation

> +			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
> +				 */

fix comment format


> +	/*add root */
> +	arr[i] = xzalloc(strlen("/") + 1);
> +	if (!arr[i])
> +		return -1;

return -ENOMEM?

> +int iget(int inode_no, struct ext2_inode *inode)
> +{
> +	if (ext4fs_read_inode(ext4fs_root, inode_no, inode) == 0)
> +		return -1;
> +	else
> +		return 0;
> +}

rm else

> +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);

free(0) is already protected for you

> +	/*single indirect */
> +	unsigned int *SI_buffer = NULL;
> +	long int SI_blockno;
> +	unsigned int *SI_start_addr = NULL;

no caps in variable names

> +	/*allocation of direct blocks */

this

> +	/*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);

and these three comments don't seem to add any real value, given the
names of the functions.

> +	if (inode->b.blocks.tripple_indir_block != 0) {
> +		TIGP_buffer = (unsigned int *)xzalloc(fs->blksz);

s/tripple/triple/g

s/TIGP/tigp/g

also buy horizontal indentation space via

	if (inode->b.blocks.tripple_indir_block == 0)
		goto fail;
	TIGP_buffer = (unsigned int *)xzalloc(fs->blksz);
	...

> +				if (fs->blksz != 1024) {
> +					bg_idx = (*TIP_buffer) / (uint32_t)
> +					    ext4fs_root->sblock.
> +					    blocks_per_group;

also assign ext4fs_root->sblock.blocks_per_group to a function local
variable, to avoid tight right-justification like this.

This is a lot of code with recurring CodingStyle review patterns, so
I'm stopping my review here.  Please detect and fix the other
occurrences and resubmit.

Thank you for your contribution!

Kim

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [U-Boot] [PATCH 2/2] ext4fs write support
  2011-12-15 17:39 [U-Boot] [PATCH 2/2] ext4fs write support uma.shankar at samsung.com
  2011-12-15 22:20 ` Kim Phillips
@ 2011-12-16 16:10 ` Mike Frysinger
  2011-12-28  2:23 ` [U-Boot] [PATCH V3 " uma.shankar at samsung.com
  2 siblings, 0 replies; 14+ messages in thread
From: Mike Frysinger @ 2011-12-16 16:10 UTC (permalink / raw)
  To: u-boot

this needs to be behind a CONFIG_EXT4_WRITE or something similar.  most people 
want to read their fs's, not write them.
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20111216/77ca0825/attachment.pgp>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [U-Boot] [PATCH V3 2/2] ext4fs write support
  2011-12-15 17:39 [U-Boot] [PATCH 2/2] ext4fs write support uma.shankar at samsung.com
  2011-12-15 22:20 ` Kim Phillips
  2011-12-16 16:10 ` Mike Frysinger
@ 2011-12-28  2:23 ` uma.shankar at samsung.com
  2012-01-05 15:25   ` Wolfgang Denk
                     ` (2 more replies)
  2 siblings, 3 replies; 14+ messages in thread
From: uma.shankar at samsung.com @ 2011-12-28  2:23 UTC (permalink / raw)
  To: u-boot

From: Uma Shankar <uma.shankar@samsung.com>

Signed-off-by: Uma Shankar <uma.shankar@samsung.com>
Signed-off-by: Manjunatha C Achar <a.manjunatha@samsung.com>
Signed-off-by: Iqbal Shareef <iqbal.ams@samsung.com>
Signed-off-by: Hakgoo Lee <goodguy.lee@samsung.com>
---
Changes for v2:
	- Code cleanup, changed comment style
	- camel case removed, resolved code alignment issues
	- memory allocation logic changed, removed busybox logic
	- Modified ext4 load to remove grub dependency (GPLv3)
	- Introduced new Config for ext4 write 

Changes for v1:
	- Removed checkpatch warnings and errors
	- Moved common API's of ext2 and ext4 to one generic header file

 common/cmd_ext4.c      |  141 +++++
 fs/ext4/Makefile       |    1 +
 fs/ext4/README         |   46 ++
 fs/ext4/crc16.c        |   62 +++
 fs/ext4/crc16.h        |   16 +
 fs/ext4/ext4_common.c  | 1380 ++++++++++++++++++++++++++++++++++++++++++++++++
 fs/ext4/ext4_common.h  |   20 +
 fs/ext4/ext4_journal.c |  662 +++++++++++++++++++++++
 fs/ext4/ext4_journal.h |  147 +++++
 fs/ext4/ext4fs.c       |  972 ++++++++++++++++++++++++++++++++++
 include/ext4fs.h       |   12 +
 11 files changed, 3459 insertions(+), 0 deletions(-)
 create mode 100644 fs/ext4/README
 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 85343db..b7c3ae0 100644
--- a/common/cmd_ext4.c
+++ b/common/cmd_ext4.c
@@ -47,6 +47,10 @@
 
 uint64_t total_sector;
 uint64_t part_offset;
+#if defined(CONFIG_CMD_EXT4_WRITE)
+static uint64_t part_size;
+static uint16_t cur_part = 1;
+#endif
 
 #define DOS_PART_MAGIC_OFFSET		0x1fe
 #define DOS_FS_TYPE_OFFSET		0x36
@@ -234,9 +238,146 @@ static int do_ext4_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
 
 	ext4fs_close();
 	deinit_fs(fs->dev_desc);
+
+	return 0;
+}
+
+#if defined(CONFIG_CMD_EXT4_WRITE)
+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_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;
+		}
+		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(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");
+
+#endif
+
 U_BOOT_CMD(ext4ls, 4, 1, do_ext4_ls,
 	   "list files in a directory (default /)",
 	   "<interface> <dev[:part]> [directory]\n"
diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile
index 850f821..548d464 100644
--- a/fs/ext4/Makefile
+++ b/fs/ext4/Makefile
@@ -31,6 +31,7 @@ LIB	= $(obj)libext4fs.o
 
 AOBJS	=
 COBJS-$(CONFIG_CMD_EXT4) := ext4fs.o ext4_common.o
+COBJS-$(CONFIG_CMD_EXT4_WRITE) += ext4_journal.o crc16.o
 
 SRCS	:= $(AOBJS:.o=.S) $(COBJS-y:.o=.c)
 OBJS	:= $(addprefix $(obj),$(AOBJS) $(COBJS-y))
diff --git a/fs/ext4/README b/fs/ext4/README
new file mode 100644
index 0000000..7f86279
--- /dev/null
+++ b/fs/ext4/README
@@ -0,0 +1,46 @@
+This patch series adds support for ext4 ls,load and write features in uboot
+Journaling is supported for write feature.
+
+To Enable ext4 ls and load commands, modify the board specific config file with
+#define CONFIG_CMD_EXT2
+#define CONFIG_CMD_EXT4
+
+To enable ext4 write command, modify the board specific config file with
+#define CONFIG_CMD_EXT2
+#define CONFIG_CMD_EXT4
+#define CONFIG_CMD_EXT4_WRITE
+
+Steps to test:
+
+1. After applying the patch, ext4 specific commands can be seen
+   in the boot loader prompt using
+        UBOOT #help
+
+        ext4load- load binary file from a Ext4 file system
+        ext4ls  - list files in a directory (default /)
+        ext4write- create a file in ext4 formatted partition
+
+2. To list the files in ext4 formatted partition, execute
+        ext4ls <interface> <dev[:part]> [directory]
+        For example:
+        UBOOT #ext4ls mmc 0:5 /usr/lib
+
+3. To read and load a file from an ext4 formatted partition to RAM, execute
+        ext4load <interface> <dev[:part]> [addr] [filename] [bytes]
+        For example:
+        UBOOT #ext4load mmc 2:2 0x30007fc0 uImage
+
+4. To write a file to a ext4 formatted partition.
+        a) First load a file to RAM at a particular address for example 0x30007fc0.
+        Now execute ext4write command
+        ext4write <interface> <dev[:part]> [filename] [Address] [sizebytes]
+        For example:
+        UBOOT #ext4write mmc 2:2 /boot/uImage 0x30007fc0 6183120
+        (here 6183120 is the size of the file to be written)
+        Note: Absolute path is required for the file to be written
+
+References :
+	-- ext4 implementation in Linux Kernel
+	-- Uboot existing ext2 load and ls implementation
+	-- Journaling block device JBD2 implementation in linux Kernel
+
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@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 d014360..881b6de 100644
--- a/fs/ext4/ext4_common.c
+++ b/fs/ext4/ext4_common.c
@@ -20,6 +20,13 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+/*
+ * 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>
@@ -27,7 +34,12 @@
 #include <asm/byteorder.h>
 #include <linux/stat.h>
 #include <linux/time.h>
+#if defined(CONFIG_CMD_EXT4_WRITE)
+#include "ext4_journal.h"
+#include "crc16.h"
+#else
 #include "ext4_common.h"
+#endif
 #include <stddef.h>
 
 struct ext2_data *ext4fs_root;
@@ -44,6 +56,1374 @@ int ext4fs_indir3_size;
 int ext4fs_indir3_blkno = -1;
 struct ext2_inode *g_parent_inode;
 
+#if defined(CONFIG_CMD_EXT4_WRITE)
+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;
+	unsigned char *temp_ptr = NULL;
+	unsigned 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, sec_buf);
+			temp_ptr = sec_buf;
+			memcpy((temp_ptr + remainder),
+			       (unsigned char *)buf, size);
+			fs->dev_desc->block_write(fs->dev_desc->dev,
+						  startblock, 1, 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, sec_buf);
+			temp_ptr = 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;
+	int count = 1;
+	int j = 0;
+
+	/* get the blocksize of the filesystem */
+	unsigned char *ptr = buffer;
+	while (*ptr == 255) {
+		ptr++;
+		count += 8;
+		if (count > 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;
+	int count = 0;
+	int 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;
+
+		*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;
+
+		*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 * 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;
+
+	*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 * 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;
+
+	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;
+	}
+
+	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;
+
+	zero_buffer = zalloc(fs->blksz);
+	if (!zero_buffer) {
+		printf("No Memory\n");
+		return;
+	}
+	root_first_block_buffer = (char *)zalloc(fs->blksz);
+	if (!root_first_block_buffer) {
+		free(zero_buffer);
+		printf("No Memory\n");
+		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;
+
+	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:Allocate new block\n");
+
+				if (direct_blk_idx == INDIRECT_BLOCKS - 1) {
+					printf("Directory exceeds 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:
+	free(zero_buffer);
+	free(root_first_block_buffer);
+}
+
+static int search_dir(struct ext2_inode *parent_inode, char *dirname)
+{
+	int status;
+	int inodeno;
+	int totalbytes;
+	int templength;
+	int direct_blk_idx;
+	long int blknr;
+	int found = 0;
+	char *ptr = NULL;
+	unsigned char *block_buffer = NULL;
+	struct ext2_dirent *dir = NULL;
+	struct ext2_dirent *previous_dir = NULL;
+	struct ext_filesystem *fs = get_fs();
+
+	/* 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 = zalloc(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;
+
+		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) {
+			free(block_buffer);
+			block_buffer = NULL;
+			return inodeno;
+		}
+
+		free(block_buffer);
+		block_buffer = NULL;
+	}
+
+ fail:
+	free(block_buffer);
+
+	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] = zalloc(strlen("/") + 1);
+	if (!arr[i])
+		return -ENOMEM;
+
+	arr[i++] = "/";
+
+	/* add each path entry after root */
+	while (token != NULL) {
+		arr[i] = zalloc(strlen(token) + 1);
+		if (!arr[i])
+			return -ENOMEM;
+		memcpy(arr[i++], token, strlen(token));
+		token = strtok(NULL, "/");
+	}
+	arr[i] = NULL;
+
+	return 0;
+}
+
+int iget(int inode_no, struct ext2_inode *inode)
+{
+	if (ext4fs_read_inode(ext4fs_root, inode_no, inode) == 0)
+		return -1;
+
+	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)
+{
+	int i;
+	int depth = 0;
+	int matched_inode_no;
+	int result_inode_no = -1;
+	char **ptr = NULL;
+	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;
+
+	if (*dirname != '/') {
+		printf("Please supply Absolute path\n");
+		return -1;
+	}
+
+	/* TODO: input validation make equivalent to linux */
+	/* get the memory size */
+	depth_dirname = (char *)zalloc(strlen(dirname) + 1);
+	if (!depth_dirname)
+		return -ENOMEM;
+
+	memcpy(depth_dirname, dirname, strlen(dirname));
+	depth = find_dir_depth(depth_dirname);
+	parse_dirname = (char *)zalloc(strlen(dirname) + 1);
+	if (!parse_dirname)
+		goto fail;
+	memcpy(parse_dirname, dirname, strlen(dirname));
+
+	/* allocate memory for each directory level */
+	ptr = (char **)zalloc((depth) * sizeof(char *));
+	if (!ptr)
+		goto fail;
+	if (parse_path(ptr, parse_dirname))
+		goto fail;
+	parent_inode = (struct ext2_inode *)
+	    zalloc(sizeof(struct ext2_inode));
+	if (!parent_inode)
+		goto fail;
+	first_inode = (struct ext2_inode *)
+	    zalloc(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:
+	free(depth_dirname);
+	free(parse_dirname);
+	free(ptr);
+	free(parent_inode);
+	free(first_inode);
+
+	return result_inode_no;
+}
+
+static int check_filename(char *filename, unsigned int blknr)
+{
+	unsigned int first_block_no_of_root;
+	int totalbytes = 0;
+	int templength = 0;
+	int status, inodeno;
+	int found = 0;
+	char *root_first_block_buffer = NULL;
+	char *root_first_block_addr = NULL;
+	struct ext2_dirent *dir = NULL;
+	struct ext2_dirent *previous_dir = NULL;
+	char *ptr = NULL;
+	struct ext_filesystem *fs = get_fs();
+
+	/* get the first block of root */
+	first_block_no_of_root = blknr;
+	root_first_block_buffer = (char *)zalloc(fs->blksz);
+	if (!root_first_block_buffer)
+		return -ENOMEM;
+	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;
+
+	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
+		 */
+		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:
+	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;
+}
+
+long int get_new_blk_no(void)
+{
+	short i;
+	short status;
+	int remainder;
+	unsigned int bg_idx;
+	static int prev_bg_bitmap_index = -1;
+	unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
+	struct ext_filesystem *fs = get_fs();
+	char *journal_buffer = (char *)zalloc(fs->blksz);
+	char *zero_buffer = (char *)zalloc(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 / blk_per_grp;
+		} else {
+			bg_idx = fs->curr_blkno / blk_per_grp;
+			remainder = fs->curr_blkno % blk_per_grp;
+			if (!remainder)
+				bg_idx--;
+		}
+
+		/*
+		 * To skip completely filled block group bitmaps
+		 * Optimize the block allocation
+		 */
+		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 + blk_per_grp;
+			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:
+	free(journal_buffer);
+	free(zero_buffer);
+
+	return fs->curr_blkno;
+ fail:
+	free(journal_buffer);
+	free(zero_buffer);
+
+	return -1;
+}
+
+int get_new_inode_no(void)
+{
+	short i;
+	short status;
+	unsigned int ibmap_idx;
+	static int prev_inode_bitmap_index = -1;
+	unsigned int inodes_per_grp = ext4fs_root->sblock.inodes_per_group;
+	struct ext_filesystem *fs = get_fs();
+	char *journal_buffer = (char *)zalloc(fs->blksz);
+	char *zero_buffer = (char *)zalloc(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 * inodes_per_grp);
+				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 / inodes_per_grp;
+		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:
+	free(journal_buffer);
+	free(zero_buffer);
+
+	return fs->curr_inode_no;
+ fail:
+	free(journal_buffer);
+	free(zero_buffer);
+
+	return -1;
+
+}
+
+static void alloc_single_indirect_block(struct ext2_inode *file_inode,
+					unsigned int *total_remaining_blocks,
+					unsigned int *no_blks_reqd)
+{
+	short i;
+	short status;
+	long int actual_block_no;
+	long int si_blockno;
+	/*si :single indirect */
+	unsigned int *si_buffer = NULL;
+	unsigned int *si_start_addr = NULL;
+	struct ext_filesystem *fs = get_fs();
+
+	if (*total_remaining_blocks != 0) {
+		si_buffer = zalloc(fs->blksz);
+		if (!si_buffer) {
+			printf("No Memory\n");
+			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:
+	free(si_start_addr);
+
+	return;
+}
+
+static void alloc_double_indirect_block(struct ext2_inode *file_inode,
+					unsigned int *total_remaining_blocks,
+					unsigned int *no_blks_reqd)
+{
+	short i;
+	short j;
+	short status;
+	long int actual_block_no;
+	/* di:double indirect */
+	long int di_blockno_parent;
+	long int 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 = zalloc(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 = zalloc(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);
+			/* 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);
+			free(di_child_buff_start);
+			di_child_buff_start = NULL;
+
+			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:
+	free(di_block_start_addr);
+
+	return;
+}
+
+static void alloc_triple_indirect_block(struct ext2_inode *file_inode,
+					unsigned int *total_remaining_blocks,
+					unsigned int *no_blks_reqd)
+{
+	short i;
+	short j;
+	short k;
+	long int actual_block_no;
+	/* ti: Triple Indirect */
+	long int ti_gp_blockno;
+	long int ti_parent_blockno;
+	long int 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 = zalloc(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 = zalloc(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 = zalloc(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 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\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);
+				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);
+			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.triple_indir_block = ti_gp_blockno;
+	}
+ fail:
+	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;
+
+	/* 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;
+	}
+
+	alloc_single_indirect_block(file_inode, &total_remaining_blocks,
+				    &no_blks_reqd);
+	alloc_double_indirect_block(file_inode, &total_remaining_blocks,
+				    &no_blks_reqd);
+	alloc_triple_indirect_block(file_inode, &total_remaining_blocks,
+				    &no_blks_reqd);
+	*total_no_of_block += no_blks_reqd;
+
+	return;
+}
+
+#endif
 static struct ext4_extent_header *ext4fs_get_extent_block(struct ext2_data *
 			data, char *buf, struct ext4_extent_header *ext_block,
 			uint32_t fileblock, int log2_blksz)
diff --git a/fs/ext4/ext4_common.h b/fs/ext4/ext4_common.h
index a0e04e0..bcf57d2 100644
--- a/fs/ext4/ext4_common.h
+++ b/fs/ext4/ext4_common.h
@@ -45,4 +45,24 @@
 extern unsigned long part_offset;
 int ext4fs_read_inode(struct ext2_data *data, int ino,
 		      struct ext2_inode *inode);
+
+#if defined(CONFIG_CMD_EXT4_WRITE)
+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
 #endif
diff --git a/fs/ext4/ext4_journal.c b/fs/ext4/ext4_journal.c
new file mode 100644
index 0000000..f40fb4d
--- /dev/null
+++ b/fs/ext4/ext4_journal.c
@@ -0,0 +1,662 @@
+/*
+ * (C) Copyright 2011 Samsung Electronics
+ * EXT4 filesystem implementation in Uboot by
+ * Uma Shankar <uma.shankar@samsung.com>
+ * Manjunatha C Achar <a.manjunatha@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 *)zalloc
+		    (sizeof(struct journal_log));
+		if (!journal_ptr[i])
+			goto fail;
+		dirty_block_ptr[i] = (struct dirty_blocks *)
+		    zalloc(sizeof(struct dirty_blocks));
+		if (!dirty_block_ptr[i])
+			goto fail;
+		journal_ptr[i]->buf = NULL;
+		journal_ptr[i]->blknr = -1;
+
+		dirty_block_ptr[i]->buf = NULL;
+		dirty_block_ptr[i]->blknr = -1;
+	}
+
+	if (fs->blksz == 4096) {
+		temp = (char *)zalloc(fs->blksz);
+		if (!temp)
+			goto fail;
+		journal_ptr[gindex]->buf = (char *)zalloc(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 *)zalloc(fs->blksz);
+		if (!journal_ptr[gindex]->buf)
+			goto fail;
+		memcpy(journal_ptr[gindex]->buf, fs->sb, SUPERBLOCK_SIZE);
+		journal_ptr[gindex++]->blknr = 1;
+	}
+
+	/* Check the file system state using journal super block */
+	if (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;
+	for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
+		if (dirty_block_ptr[i]->blknr == -1)
+			break;
+		if (dirty_block_ptr[i]->buf)
+			free(dirty_block_ptr[i]->buf);
+	}
+
+	for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
+		if (journal_ptr[i]->blknr == -1)
+			break;
+		if (journal_ptr[i]->buf)
+			free(journal_ptr[i]->buf);
+	}
+
+	for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
+		if (journal_ptr[i])
+			free(journal_ptr[i]);
+		if (dirty_block_ptr[i])
+			free(dirty_block_ptr[i]);
+	}
+	gindex = 0;
+	gd_index = 0;
+	jrnl_blk_idx = 1;
+
+	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 *)zalloc(fs->blksz);
+		if (!journal_ptr[gindex]->buf)
+			return -ENOMEM;
+		memcpy(journal_ptr[gindex]->buf, gd_table, fs->blksz);
+		gd_table += fs->blksz;
+		journal_ptr[gindex++]->blknr = var++;
+	}
+
+	return 0;
+}
+
+/*
+ * This function stores the backup copy of meta data in RAM
+ * journal_buffer -- Buffer containing meta data
+ * blknr -- Block number on disk of the meta data buffer
+ */
+int log_journal(char *journal_buffer, long int blknr)
+{
+	struct ext_filesystem *fs = get_fs();
+	short i;
+
+	if (!journal_buffer) {
+		printf("Invalid input arguments %s\n", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
+		if (journal_ptr[i]->blknr == -1)
+			break;
+		if (journal_ptr[i]->blknr == blknr)
+			return 0;
+	}
+
+	journal_ptr[gindex]->buf = (char *)zalloc(fs->blksz);
+	if (!journal_ptr[gindex]->buf)
+		return -ENOMEM;
+
+	memcpy(journal_ptr[gindex]->buf, journal_buffer, fs->blksz);
+	journal_ptr[gindex++]->blknr = blknr;
+
+	return 0;
+}
+
+/*
+ * This function stores the modified meta data in RAM
+ * metadata_buffer -- Buffer containing meta data
+ * blknr -- Block number on disk of the meta data buffer
+ */
+int put_metadata(char *metadata_buffer, long int blknr)
+{
+	struct ext_filesystem *fs = get_fs();
+	if (!metadata_buffer) {
+		printf("Invalid input arguments %s\n", __func__);
+		return -EINVAL;
+	}
+	dirty_block_ptr[gd_index]->buf = (char *)zalloc(fs->blksz);
+	if (!dirty_block_ptr[gd_index]->buf)
+		return -ENOMEM;
+	memcpy(dirty_block_ptr[gd_index]->buf, metadata_buffer, fs->blksz);
+	dirty_block_ptr[gd_index++]->blknr = blknr;
+
+	return 0;
+}
+
+void print_revoke_blks(char *revk_blk)
+{
+	int offset;
+	int max;
+	long int blocknr;
+	struct journal_revoke_header_t *header;
+
+	if (revk_blk == NULL)
+		return;
+
+	header = (struct journal_revoke_header_t *)revk_blk;
+	offset = sizeof(struct journal_revoke_header_t);
+	max = 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 *)
+	    zalloc(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 = NULL;
+	struct ext_filesystem *fs = get_fs();
+	if (buffer == NULL) {
+		printf("buffer ptr is NULL\n");
+		return;
+	}
+	node = _get_node();
+	if (!node) {
+		printf("_get_node: malloc failed\n");
+		return;
+	}
+
+	node->content = (char *)zalloc(fs->blksz);
+	if (node->content == NULL)
+		return;
+	memcpy(node->content, buffer, fs->blksz);
+
+	if (first_node == TRUE) {
+		revk_blk_list = node;
+		prev_node = node;
+		first_node = FALSE;
+	} else {
+		prev_node->next = node;
+		prev_node = node;
+	}
+
+	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;
+	int max;
+	long int blocknr;
+	char *revk_blk;
+	struct revoke_blk_list *tmp_revk_node = revk_blk_list;
+	while (tmp_revk_node != NULL) {
+		revk_blk = tmp_revk_node->content;
+
+		header = (struct journal_revoke_header_t *)revk_blk;
+		if (sequence_no <= 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 *)zalloc(fs->blksz);
+	char *metadata_buff = (char *)zalloc(fs->blksz);
+	if (!temp_buff || !metadata_buff)
+		goto fail;
+	i = prev_desc_logical_no;
+	ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
+			  (struct ext2_inode *)&inode_journal);
+	blknr = read_allocated_block((struct ext2_inode *)
+				     &inode_journal, i);
+	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:
+	free(temp_buff);
+	free(metadata_buff);
+}
+
+void print_jrnl_status(int recovery_flag)
+{
+	if (recovery_flag == RECOVER)
+		printf("Journal Recovery Completed\n");
+	else
+		printf("Journal Scan Completed\n");
+
+	return;
+}
+
+int check_journal_state(int recovery_flag)
+{
+	int i;
+	int DB_FOUND = NO;
+	long int blknr;
+	int transaction_state = TRANSACTION_COMPLETE;
+	int prev_desc_logical_no = 0;
+	int curr_desc_logical_no = 0;
+	int ofs, flags, block;
+	struct ext2_inode inode_journal;
+	struct journal_superblock_t *jsb = NULL;
+	struct journal_header_t *jdb = NULL;
+	char *p_jdb = NULL;
+	struct ext3_journal_block_tag *tag = NULL;
+	char *temp_buff = NULL;
+	char *temp_buff1 = NULL;
+	struct ext_filesystem *fs = get_fs();
+
+	temp_buff = (char *)zalloc(fs->blksz);
+	if (!temp_buff)
+		return -ENOMEM;
+	temp_buff1 = (char *)zalloc(fs->blksz);
+	if (!temp_buff1) {
+		free(temp_buff);
+		return -ENOMEM;
+	}
+
+	ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
+	blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK);
+	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);
+		/* 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);
+		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)
+{
+	int i;
+	long int jsb_blknr;
+	struct journal_header_t jdb;
+	struct ext3_journal_block_tag tag;
+	struct ext2_inode inode_journal;
+	struct journal_superblock_t *jsb = NULL;
+	char *buf = NULL;
+	char *temp = NULL;
+	struct ext_filesystem *fs = get_fs();
+	char *temp_buff = (char *)zalloc(fs->blksz);
+	if (!temp_buff)
+		return;
+
+	ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
+	jsb_blknr = read_allocated_block(&inode_journal,
+					 EXT2_JOURNAL_SUPERBLOCK);
+	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 *)zalloc(fs->blksz);
+	if (!buf) {
+		free(temp_buff);
+		return;
+	}
+	temp = buf;
+	memcpy(buf, &jdb, sizeof(struct journal_header_t));
+	temp += sizeof(struct journal_header_t);
+
+	for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
+		if (journal_ptr[i]->blknr == -1)
+			break;
+
+		tag.block = 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 *)zalloc(fs->blksz);
+	if (!temp_buff)
+		return;
+
+	ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
+	jsb_blknr = read_allocated_block(&inode_journal,
+					 EXT2_JOURNAL_SUPERBLOCK);
+	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 *)zalloc(fs->blksz);
+	if (!buf) {
+		free(temp_buff);
+		return;
+	}
+	memcpy(buf, &jdb, sizeof(struct journal_header_t));
+	put_ext4((uint64_t) (blknr * fs->blksz), buf, (uint32_t) fs->blksz);
+
+	free(temp_buff);
+	free(buf);
+}
+
+void 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..e940b87
--- /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@samsung.com>
+ * Manjunatha C Achar <a.manjunatha@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 2db044d..825f2e6 100644
--- a/fs/ext4/ext4fs.c
+++ b/fs/ext4/ext4fs.c
@@ -20,6 +20,13 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+/*
+ *  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>
@@ -27,7 +34,11 @@
 #include <linux/time.h>
 #include <ext_common.h>
 #include <ext4fs.h>
+#if defined(CONFIG_CMD_EXT4_WRITE)
+#include "ext4_journal.h"
+#else
 #include "ext4_common.h"
+#endif
 
 int ext4fs_symlinknest;
 block_dev_desc_t *ext4_dev_desc;
@@ -217,3 +228,964 @@ int ext4fs_read(char *buf, unsigned len)
 
 	return  ext4fs_read_file(ext4fs_file, 0, len, buf);
 }
+
+#if defined(CONFIG_CMD_EXT4_WRITE)
+static void ext4fs_update(void)
+{
+	short i;
+	update_journal();
+	struct ext_filesystem *fs = get_fs();
+
+	/* update  super block */
+	put_ext4((uint64_t) (SUPERBLOCK_SIZE),
+		 (struct ext2_sblock *)fs->sb, (uint32_t) SUPERBLOCK_SIZE);
+
+	/* update block groups */
+	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], fs->blksz);
+	}
+
+	/* update inode table groups */
+	for (i = 0; i < fs->no_blkgrp; i++) {
+		put_ext4((uint64_t) (fs->gd[i].inode_id * fs->blksz),
+			 fs->inode_bmaps[i], fs->blksz);
+	}
+
+	/* update the block group descriptor table */
+	put_ext4((uint64_t) (fs->gdtable_blkno * fs->blksz),
+		 (struct ext2_block_group *)fs->gdtable,
+		 (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 memory for gdtable */
+	fs->gdtable = (char *)zalloc(fs->blksz * fs->no_blk_pergdt);
+	if (!fs->gdtable)
+		return -ENOMEM;
+	/*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:
+	free(fs->gdtable);
+	fs->gdtable = NULL;
+
+	return -1;
+}
+
+static void delete_single_indirect_block(struct ext2_inode *inode)
+{
+	struct ext2_block_group *gd = NULL;
+	static int prev_bg_bmap_idx = -1;
+	long int blknr;
+	int remainder;
+	int bg_idx;
+	int status;
+	unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
+	struct ext_filesystem *fs = get_fs();
+	char *journal_buffer = (char *)zalloc(fs->blksz);
+	if (!journal_buffer) {
+		printf("No memory\n");
+		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 / blk_per_grp;
+		} else {
+			bg_idx = blknr / blk_per_grp;
+			remainder = blknr % blk_per_grp;
+			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_bmap_idx != 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_bmap_idx = bg_idx;
+		}
+	}
+ fail:
+	free(journal_buffer);
+
+	return;
+
+}
+
+static void delete_double_indirect_block(struct ext2_inode *inode)
+{
+	int i;
+	short status;
+	static int prev_bg_bmap_idx = -1;
+	long int blknr;
+	int remainder;
+	int bg_idx;
+	unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
+	unsigned int *di_buffer = NULL;
+	unsigned int *DIB_start_addr = NULL;
+	struct ext2_block_group *gd = NULL;
+	struct ext_filesystem *fs = get_fs();
+	char *journal_buffer = (char *)zalloc(fs->blksz);
+	if (!journal_buffer) {
+		printf("No memory\n");
+		return;
+	}
+	/* get the block group descriptor table */
+	gd = (struct ext2_block_group *)fs->gdtable;
+
+	if (inode->b.blocks.double_indir_block != 0) {
+		di_buffer = (unsigned int *)zalloc(fs->blksz);
+		if (!di_buffer) {
+			printf("No memory\n");
+			return;
+		}
+		DIB_start_addr = (unsigned int *)di_buffer;
+		blknr = inode->b.blocks.double_indir_block;
+		status = ext2fs_devread(blknr * fs->sect_perblk, 0, fs->blksz,
+					(char *)di_buffer);
+		for (i = 0; i < fs->blksz / sizeof(int); i++) {
+			if (*di_buffer == 0)
+				break;
+
+			debug("DICB releasing %u\n", *di_buffer);
+			if (fs->blksz != 1024) {
+				bg_idx = (*di_buffer) / blk_per_grp;
+			} else {
+				bg_idx = (*di_buffer) / blk_per_grp;
+				remainder = (*di_buffer) % blk_per_grp;
+				if (!remainder)
+					bg_idx--;
+			}
+			reset_block_bmap(*di_buffer,
+					 fs->blk_bmaps[bg_idx], bg_idx);
+			di_buffer++;
+			gd[bg_idx].free_blocks++;
+			fs->sb->free_blocks++;
+			/* journal backup */
+			if (prev_bg_bmap_idx != 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_bmap_idx = 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 / blk_per_grp;
+		} else {
+			bg_idx = blknr / blk_per_grp;
+			remainder = blknr % blk_per_grp;
+			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_bmap_idx != 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_bmap_idx = bg_idx;
+		}
+		debug("DIPB releasing %ld\n", blknr);
+	}
+ fail:
+	free(DIB_start_addr);
+	free(journal_buffer);
+
+	return;
+}
+
+static void delete_triple_indirect_block(struct ext2_inode *inode)
+{
+	int i, j;
+	short status;
+	static int prev_bg_bmap_idx = -1;
+	long int blknr;
+	int remainder;
+	int bg_idx;
+	unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
+	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 = NULL;
+	struct ext_filesystem *fs = get_fs();
+	char *journal_buffer = (char *)zalloc(fs->blksz);
+	if (!journal_buffer) {
+		printf("No memory\n");
+		return;
+	}
+	/* get block group descriptor table */
+	gd = (struct ext2_block_group *)fs->gdtable;
+
+	if (inode->b.blocks.triple_indir_block != 0) {
+		tigp_buffer = (unsigned int *)zalloc(fs->blksz);
+		if (!tigp_buffer) {
+			printf("No memory\n");
+			return;
+		}
+		tib_start_addr = (unsigned int *)tigp_buffer;
+		blknr = inode->b.blocks.triple_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("tigp buffer releasing %u\n", *tigp_buffer);
+
+			tip_buffer = (unsigned int *)zalloc(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) / blk_per_grp;
+				} else {
+					bg_idx = (*tip_buffer) / blk_per_grp;
+
+					remainder = (*tip_buffer) % blk_per_grp;
+					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_bmap_idx != 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_bmap_idx = bg_idx;
+				}
+			}
+			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) / blk_per_grp;
+			} else {
+				bg_idx = (*tigp_buffer) / blk_per_grp;
+
+				remainder = (*tigp_buffer) % blk_per_grp;
+				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_bmap_idx != 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_bmap_idx = bg_idx;
+			}
+		}
+
+		/* removing the grand parent triple indirect block */
+		blknr = inode->b.blocks.triple_indir_block;
+		if (fs->blksz != 1024) {
+			bg_idx = blknr / blk_per_grp;
+		} else {
+			bg_idx = blknr / blk_per_grp;
+			remainder = blknr % blk_per_grp;
+			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_bmap_idx != 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_bmap_idx = bg_idx;
+		}
+		debug("tigp buffer itself releasing %ld\n", blknr);
+	}
+ fail:
+	free(tib_start_addr);
+	free(tipb_start_addr);
+	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 ibmap_idx;
+	char *read_buffer = NULL;
+	char *start_block_address = NULL;
+	unsigned int no_blocks;
+
+	static int prev_bg_bmap_idx = -1;
+	unsigned int inodes_per_block;
+	long int blkno;
+	unsigned int blkoff;
+	unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
+	unsigned int inode_per_grp = ext4fs_root->sblock.inodes_per_group;
+	struct ext2_inode *inode_buffer = NULL;
+	struct ext2_block_group *gd = NULL;
+	struct ext_filesystem *fs = get_fs();
+	char *journal_buffer = (char *)zalloc(fs->blksz);
+	if (!journal_buffer)
+		return -ENOMEM;
+	/* 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_FL) {
+		struct ext2fs_node *node_inode =
+		    (struct ext2fs_node *)zalloc(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 / blk_per_grp;
+			} else {
+				bg_idx = blknr / blk_per_grp;
+				remainder = blknr % blk_per_grp;
+				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_bmap_idx != 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_bmap_idx = bg_idx;
+			}
+		}
+		if (node_inode) {
+			free(node_inode);
+			node_inode = NULL;
+		}
+	} else {
+
+		delete_single_indirect_block(&inode);
+		delete_double_indirect_block(&inode);
+		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 / blk_per_grp;
+			} else {
+				bg_idx = blknr / blk_per_grp;
+				remainder = blknr % blk_per_grp;
+				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_bmap_idx != 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_bmap_idx = bg_idx;
+			}
+		}
+	}
+
+	/* from the inode no to blockno */
+	inodes_per_block = fs->blksz / fs->inodesz;
+	ibmap_idx = inodeno / inode_per_grp;
+
+	/* get the block no */
+	inodeno--;
+	blkno = __le32_to_cpu(gd[ibmap_idx].inode_table_id) +
+	    (inodeno % __le32_to_cpu(inode_per_grp)) / 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 *)zalloc(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[ibmap_idx], ibmap_idx);
+	gd[ibmap_idx].free_inodes++;
+	fs->sb->free_inodes++;
+	/* journal backup */
+	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;
+
+	ext4fs_update();
+	ext4fs_deinit();
+
+	if (ext4fs_init() != 0) {
+		printf("error in File System init\n");
+		goto fail;
+	}
+
+	free(start_block_address);
+	free(journal_buffer);
+
+	return 0;
+ fail:
+	free(start_block_address);
+	free(journal_buffer);
+
+	return -1;
+}
+
+int ext4fs_init(void)
+{
+	short status;
+	int i;
+	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;
+
+	/* get the superblock */
+	fs->sb = (struct ext2_sblock *)zalloc(SUPERBLOCK_SIZE);
+	if (!fs->sb)
+		return -ENOMEM;
+	if (!ext2fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE,
+			    (char *)fs->sb))
+		goto fail;
+
+	/* init journal */
+	if (init_journal())
+		goto fail;
+
+	/* get total no of blockgroups */
+	fs->no_blkgrp = (uint32_t) ext4fs_div_roundup
+	    ((ext4fs_root->sblock.total_blocks -
+	      ext4fs_root->sblock.first_data_block),
+	     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("Error in getting the block group descriptor table\n");
+		goto fail;
+	}
+	fs->gd = (struct ext2_block_group *)fs->gdtable;
+
+	/* load all the available bitmap block of the partition */
+	fs->blk_bmaps = (unsigned char **)zalloc
+	    (fs->no_blkgrp * sizeof(char *));
+	if (!fs->blk_bmaps)
+		goto fail;
+	for (i = 0; i < fs->no_blkgrp; i++) {
+		fs->blk_bmaps[i] = (unsigned char *)zalloc(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 * fs->sect_perblk, 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 **)zalloc
+	    (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 *)zalloc(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 * fs->sect_perblk,
+					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 *)zalloc(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, 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);
+	free(fs->sb);
+	fs->sb = NULL;
+
+	if (fs->blk_bmaps) {
+		for (i = 0; i < fs->no_blkgrp; 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++) {
+			free(fs->inode_bmaps[i]);
+			fs->inode_bmaps[i] = NULL;
+		}
+		free(fs->inode_bmaps);
+		fs->inode_bmaps = NULL;
+	}
+
+	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 bytes_reqd_for_file;
+	unsigned int blks_reqd_for_file;
+	unsigned int blocks_remaining;
+	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 ibmap_idx;
+	struct ext_filesystem *fs = get_fs();
+	g_parent_inode = (struct ext2_inode *)zalloc(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 */
+	bytes_reqd_for_file = sizebytes;
+	blks_reqd_for_file = bytes_reqd_for_file / fs->blksz;
+	if (bytes_reqd_for_file % fs->blksz != 0) {
+		blks_reqd_for_file++;
+		debug("total bytes for a file %u\n", blks_reqd_for_file);
+	}
+	blocks_remaining = blks_reqd_for_file;
+	/* test for available space in partition */
+	if (fs->sb->free_blocks < blks_reqd_for_file) {
+		printf("Not enough space on partition !!!\n");
+		goto fail;
+	}
+
+	update_parent_dentry(filename, &inodeno, FILETYPE_REG);
+	/* prepare file inode */
+	inode_buffer = zalloc(fs->inodesz);
+	if (!inode_buffer)
+		goto fail;
+	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, blocks_remaining, &blks_reqd_for_file);
+	file_inode->blockcnt = (blks_reqd_for_file * fs->blksz) / SECTOR_SIZE;
+
+	temp_ptr = (char *)zalloc(fs->blksz);
+	if (!temp_ptr)
+		goto fail;
+	ibmap_idx = inodeno / ext4fs_root->sblock.inodes_per_group;
+	inodeno--;
+	itable_blkno = __le32_to_cpu(fs->gd[ibmap_idx].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;
+	}
+	ibmap_idx = parent_inodeno / ext4fs_root->sblock.inodes_per_group;
+	parent_inodeno--;
+	parent_itable_blkno = __le32_to_cpu(fs->gd[ibmap_idx].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;
+	free(inode_buffer);
+	free(g_parent_inode);
+	g_parent_inode = NULL;
+
+	return 0;
+ fail:
+	ext4fs_deinit();
+	free(inode_buffer);
+	free(g_parent_inode);
+	g_parent_inode = NULL;
+
+	return -1;
+}
+#endif
diff --git a/include/ext4fs.h b/include/ext4fs.h
index e1eb17f..151b7b1 100644
--- a/include/ext4fs.h
+++ b/include/ext4fs.h
@@ -119,6 +119,18 @@ extern block_dev_desc_t *ext4_dev_desc;
 
 extern struct ext2_data *ext4fs_root;
 extern struct ext2fs_node *ext4fs_file;
+
+#if defined(CONFIG_CMD_EXT4_WRITE)
+extern struct ext2_inode *g_parent_inode;
+extern int gd_index;
+extern int gindex;
+
+int ext4fs_init(void);
+void ext4fs_deinit(void);
+int ext4fs_filename_check(char *filename);
+int ext4fs_write(char *fname, unsigned char *buffer, unsigned long sizebytes);
+#endif
+
 struct ext_filesystem *get_fs(void);
 int init_fs(block_dev_desc_t *);
 void deinit_fs(block_dev_desc_t *);
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [U-Boot] [PATCH V3 2/2] ext4fs write support
  2011-12-28  2:23 ` [U-Boot] [PATCH V3 " uma.shankar at samsung.com
@ 2012-01-05 15:25   ` Wolfgang Denk
  2012-01-08  4:24   ` Mike Frysinger
  2012-01-09 17:56   ` [U-Boot] [PATCH V4 " uma.shankar at samsung.com
  2 siblings, 0 replies; 14+ messages in thread
From: Wolfgang Denk @ 2012-01-05 15:25 UTC (permalink / raw)
  To: u-boot

Dear uma.shankar at samsung.com,

In message <1325039007-10611-1-git-send-email-uma.shankar@samsung.com> you wrote:
> From: Uma Shankar <uma.shankar@samsung.com>
> 
> Signed-off-by: Uma Shankar <uma.shankar@samsung.com>
> Signed-off-by: Manjunatha C Achar <a.manjunatha@samsung.com>
> Signed-off-by: Iqbal Shareef <iqbal.ams@samsung.com>
> Signed-off-by: Hakgoo Lee <goodguy.lee@samsung.com>
> ---
> Changes for v2:
> 	- Code cleanup, changed comment style
> 	- camel case removed, resolved code alignment issues
> 	- memory allocation logic changed, removed busybox logic
> 	- Modified ext4 load to remove grub dependency (GPLv3)
> 	- Introduced new Config for ext4 write 
> 
> Changes for v1:
> 	- Removed checkpatch warnings and errors
> 	- Moved common API's of ext2 and ext4 to one generic header file
> 
>  common/cmd_ext4.c      |  141 +++++
>  fs/ext4/Makefile       |    1 +
>  fs/ext4/README         |   46 ++
>  fs/ext4/crc16.c        |   62 +++
>  fs/ext4/crc16.h        |   16 +
>  fs/ext4/ext4_common.c  | 1380 ++++++++++++++++++++++++++++++++++++++++++++++++
>  fs/ext4/ext4_common.h  |   20 +
>  fs/ext4/ext4_journal.c |  662 +++++++++++++++++++++++
>  fs/ext4/ext4_journal.h |  147 +++++
>  fs/ext4/ext4fs.c       |  972 ++++++++++++++++++++++++++++++++++
>  include/ext4fs.h       |   12 +
>  11 files changed, 3459 insertions(+), 0 deletions(-)
>  create mode 100644 fs/ext4/README
>  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

Applied, thanks.

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 at denx.de
Youth doesn't excuse everything.
	-- Dr. Janice Lester (in Kirk's body), "Turnabout Intruder",
	   stardate 5928.5.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [U-Boot] [PATCH V3 2/2] ext4fs write support
  2011-12-28  2:23 ` [U-Boot] [PATCH V3 " uma.shankar at samsung.com
  2012-01-05 15:25   ` Wolfgang Denk
@ 2012-01-08  4:24   ` Mike Frysinger
  2012-01-09 17:56   ` [U-Boot] [PATCH V4 " uma.shankar at samsung.com
  2 siblings, 0 replies; 14+ messages in thread
From: Mike Frysinger @ 2012-01-08  4:24 UTC (permalink / raw)
  To: u-boot

On Tuesday 27 December 2011 21:23:27 uma.shankar at samsung.com wrote:
> From: Uma Shankar <uma.shankar@samsung.com>
> 
> Signed-off-by: Uma Shankar <uma.shankar@samsung.com>
> Signed-off-by: Manjunatha C Achar <a.manjunatha@samsung.com>
> Signed-off-by: Iqbal Shareef <iqbal.ams@samsung.com>
> Signed-off-by: Hakgoo Lee <goodguy.lee@samsung.com>

you need to note the sources of these files in the changelog

> --- a/common/cmd_ext4.c
> +++ b/common/cmd_ext4.c
>  
> +int do_ext4_write(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])

static

> +	char *filename = "/";

const

> +	int dev = 0;

considering you set dev first below, no point in setting this to 0

> +	/*get the filename */

many of the comments here are missing a space after the "/*"

> --- /dev/null
> +++ b/fs/ext4/README

docs belong in docs/

> --- /dev/null
> +++ b/fs/ext4/crc16.c
>
> +/*
> + *      crc16.c
> + *
> + * This source code is licensed under the GNU General Public License,
> + * Version 2. See the file COPYING for more details.
> + */

why can't you use the existing lib/crc16.c code ?

> --- a/fs/ext4/ext4_common.c
> +++ b/fs/ext4/ext4_common.c
> 
> +#if defined(CONFIG_CMD_EXT4_WRITE)
> +#include "ext4_journal.h"
> +#include "crc16.h"
> +#else
>  #include "ext4_common.h"
> +#endif

conditional header includes are a bad idea

> +/* To convert big endian journal superblock entries to little endian */
> +unsigned int be_le(unsigned int num)
> ...
> +/* 4-byte number */
> +unsigned int le_be(unsigned int num)

we already have swap functions in include/ you should be able to use instead 
of duplicating them

> +void reset_inode_bmap(int inode_no, unsigned char *buffer, int index)
> ...
> +
> +	return;
> +}

useless return -> delete it

> --- a/fs/ext4/ext4_common.h
> +++ b/fs/ext4/ext4_common.h
> 
> +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);
>
> --- /dev/null
> +++ b/fs/ext4/ext4_journal.h
> 
> +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);

these are a lot of bad names.  these need to be properly namespaced if you're 
going to export them.

> --- /dev/null
> +++ b/fs/ext4/ext4_journal.c
>
> +		journal_ptr[i] = (struct journal_log *)zalloc
> +		    (sizeof(struct journal_log));
> ...
> +		dirty_block_ptr[i] = (struct dirty_blocks *)
> +		    zalloc(sizeof(struct dirty_blocks));
> ...
> +		journal_ptr[gindex]->buf = (char *)zalloc(fs->blksz);
> ...
> +		journal_ptr[gindex]->buf = (char *)zalloc(fs->blksz);

useless casts.  zalloc() returns void *.  there's a bunch more throughout this 
patch.

> +void free_journal(void)
> +{
> ...
> +
> +	return;
> +}

useless return

> +void print_revoke_blks(char *revk_blk)
> +{
> ...
> +
> +	return;
> +}

useless return

> +static struct revoke_blk_list *_get_node(void)
> +{
> ...
> +
> +	return;
> +}

useless return

> +void free_revoke_blks()

needs (void)

> +	return;
> +}

useless return

> +void print_jrnl_status(int recovery_flag)
> +{
> ...
> +
> +	return;
> +}

useless return

> --- a/fs/ext4/ext4fs.c
> +++ b/fs/ext4/ext4fs.c
> 
> +static void delete_single_indirect_block(struct ext2_inode *inode)
> +{
> ...
> +
> +	return;
> +
> +}

useless return

> +static void delete_double_indirect_block(struct ext2_inode *inode)
> +{
> ...
> +
> +	return;
> +}

useless return

> +static void delete_triple_indirect_block(struct ext2_inode *inode)
> +{
> ...
> +
> +	return;
> +}

useless return

> +void ext4fs_deinit(void)
> +{
> ...
> +
> +	return;
> +}

useless return
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20120107/11d75ffc/attachment.pgp>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [U-Boot] [PATCH V4 2/2] ext4fs write support
  2011-12-28  2:23 ` [U-Boot] [PATCH V3 " uma.shankar at samsung.com
  2012-01-05 15:25   ` Wolfgang Denk
  2012-01-08  4:24   ` Mike Frysinger
@ 2012-01-09 17:56   ` uma.shankar at samsung.com
  2012-01-16  0:03     ` Mike Frysinger
  2012-05-25 15:52     ` [U-Boot] [PATCH V5 " Uma Shankar
  2 siblings, 2 replies; 14+ messages in thread
From: uma.shankar at samsung.com @ 2012-01-09 17:56 UTC (permalink / raw)
  To: u-boot

From: uma.shankar <uma.shankar@samsung.com>

Signed-off-by: Uma Shankar <uma.shankar@samsung.com>
Signed-off-by: Manjunatha C Achar <a.manjunatha@samsung.com>
Signed-off-by: Iqbal Shareef <iqbal.ams@samsung.com>
Signed-off-by: Hakgoo Lee <goodguy.lee@samsung.com>
---
Changes for v3:
        - Copyright has been updated in respective files
        - ext4fs has been made independant of ext2fs.c
        - Fixed API namespace
        - Removed endianness conversion API, used uboot defined API
          for the same
        - Fixed coding style issues
        - Moved README.ext4 file into doc folder

Changes for v2:
        - Code cleanup, changed comment style
        - camel case removed, resolved code alignment issues
        - memory allocation logic changed, removed busybox logic
        - Modified ext4 load to remove grub dependency (GPLv3)
        - Introduced new Config for ext4 write

Changes for v1:
        - Removed checkpatch warnings and errors
        - Moved common API's of ext2 and ext4 to one generic header file

 common/Makefile        |    3 +
 common/cmd_ext4.c      |  143 +++++-
 doc/README.ext4        |   43 ++
 fs/ext4/Makefile       |    4 +
 fs/ext4/crc16.c        |   62 +++
 fs/ext4/crc16.h        |   16 +
 fs/ext4/ext4_common.c  | 1346 ++++++++++++++++++++++++++++++++++++++++++++++++
 fs/ext4/ext4_common.h  |   25 +
 fs/ext4/ext4_journal.c |  666 ++++++++++++++++++++++++
 fs/ext4/ext4_journal.h |  141 +++++
 fs/ext4/ext4fs.c       |  960 ++++++++++++++++++++++++++++++++++
 include/ext4fs.h       |   12 +
 12 files changed, 3420 insertions(+), 1 deletions(-)
 create mode 100644 doc/README.ext4
 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/Makefile b/common/Makefile
index f5243f6..a088310 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -87,6 +87,9 @@ COBJS-$(CONFIG_CMD_EEPROM) += cmd_eeprom.o
 COBJS-$(CONFIG_CMD_ELF) += cmd_elf.o
 COBJS-$(CONFIG_SYS_HUSH_PARSER) += cmd_exit.o
 COBJS-$(CONFIG_CMD_EXT4) += cmd_ext4.o
+ifndef CONFIG_CMD_EXT4
+COBJS-$(CONFIG_CMD_EXT4_WRITE) += cmd_ext4.o
+endif
 COBJS-$(CONFIG_CMD_EXT2) += cmd_ext2.o
 COBJS-$(CONFIG_CMD_FAT) += cmd_fat.o
 COBJS-$(CONFIG_CMD_FDC)$(CONFIG_CMD_FDOS) += cmd_fdc.o
diff --git a/common/cmd_ext4.c b/common/cmd_ext4.c
index 2c53d2c..128db4b 100644
--- a/common/cmd_ext4.c
+++ b/common/cmd_ext4.c
@@ -37,7 +37,7 @@
 /*
  * Changelog:
  *	0.1 - Newly created file for ext4fs support. Taken from cmd_ext2.c
- *	        file in uboot. Added ext4fs ls and load support.
+ *	        file in uboot. Added ext4fs ls load and write support.
  */
 
 #include <common.h>
@@ -62,6 +62,10 @@
 
 uint64_t total_sector;
 uint64_t part_offset;
+#if defined(CONFIG_CMD_EXT4_WRITE)
+static uint64_t part_size;
+static uint16_t cur_part = 1;
+#endif
 
 #define DOS_PART_MAGIC_OFFSET	0x1fe
 #define DOS_FS_TYPE_OFFSET	0x36
@@ -254,6 +258,143 @@ static int do_ext4_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
 	return 0;
 }
 
+#if defined(CONFIG_CMD_EXT4_WRITE)
+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;
+}
+
+static int do_ext4_write(cmd_tbl_t *cmdtp, int flag, int argc,
+				char *const argv[])
+{
+	const char *filename = "/";
+	int part_length;
+	unsigned long part = 1;
+	int dev;
+	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;
+		}
+		part = simple_strtoul(++ep, NULL, 16);
+	}
+
+	/* get the filename */
+	filename = argv[3];
+
+	/* get the address in hexadecimal format (string to int) */
+	ram_address = simple_strtoul(argv[4], NULL, 16);
+
+	/* get the filesize in base 10 format */
+	file_size = simple_strtoul(argv[5], NULL, 10);
+
+	/* set the device as block device */
+	part_length = ext4fs_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(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");
+
+#endif
+
 U_BOOT_CMD(ext4ls, 4, 1, do_ext4_ls,
 	   "list files in a directory (default /)",
 	   "<interface> <dev[:part]> [directory]\n"
diff --git a/doc/README.ext4 b/doc/README.ext4
new file mode 100644
index 0000000..5937afb
--- /dev/null
+++ b/doc/README.ext4
@@ -0,0 +1,43 @@
+This patch series adds support for ext4 ls,load and write features in uboot
+Journaling is supported for write feature.
+
+To Enable ext4 ls and load commands, modify the board specific config file with
+#define CONFIG_CMD_EXT4
+
+To enable ext4 write command, modify the board specific config file with
+#define CONFIG_CMD_EXT4_WRITE
+
+Steps to test:
+
+1. After applying the patch, ext4 specific commands can be seen
+   in the boot loader prompt using
+        UBOOT #help
+
+        ext4load- load binary file from a Ext4 file system
+        ext4ls  - list files in a directory (default /)
+        ext4write- create a file in ext4 formatted partition
+
+2. To list the files in ext4 formatted partition, execute
+        ext4ls <interface> <dev[:part]> [directory]
+        For example:
+        UBOOT #ext4ls mmc 0:5 /usr/lib
+
+3. To read and load a file from an ext4 formatted partition to RAM, execute
+        ext4load <interface> <dev[:part]> [addr] [filename] [bytes]
+        For example:
+        UBOOT #ext4load mmc 2:2 0x30007fc0 uImage
+
+4. To write a file to a ext4 formatted partition.
+        a) First load a file to RAM at a particular address for example 0x30007fc0.
+        Now execute ext4write command
+        ext4write <interface> <dev[:part]> [filename] [Address] [sizebytes]
+        For example:
+        UBOOT #ext4write mmc 2:2 /boot/uImage 0x30007fc0 6183120
+        (here 6183120 is the size of the file to be written)
+        Note: Absolute path is required for the file to be written
+
+References :
+	-- ext4 implementation in Linux Kernel
+	-- Uboot existing ext2 load and ls implementation
+	-- Journaling block device JBD2 implementation in linux Kernel
+
diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile
index 7add4ab..5b86dab 100644
--- a/fs/ext4/Makefile
+++ b/fs/ext4/Makefile
@@ -31,6 +31,10 @@ LIB	= $(obj)libext4fs.o
 
 AOBJS	=
 COBJS-$(CONFIG_CMD_EXT4) := ext4fs.o ext4_common.o dev.o
+ifndef CONFIG_CMD_EXT4
+COBJS-$(CONFIG_CMD_EXT4_WRITE) := ext4fs.o ext4_common.o dev.o
+endif
+COBJS-$(CONFIG_CMD_EXT4_WRITE) += 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..02a4816
--- /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..688b871
--- /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@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 d9deefe..169388b 100644
--- a/fs/ext4/ext4_common.c
+++ b/fs/ext4/ext4_common.c
@@ -14,6 +14,8 @@
  * GRUB  --  GRand Unified Bootloader
  * Copyright (C) 2003, 2004  Free Software Foundation, Inc.
  *
+ * ext4write : Based on generic ext4 protocol.
+ *
  * 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
@@ -54,6 +56,1350 @@ int ext4fs_indir3_blkno = -1;
 struct ext2_inode *g_parent_inode;
 static int symlinknest;
 
+#if defined(CONFIG_CMD_EXT4_WRITE)
+uint32_t ext4fs_div_roundup(uint32_t size, uint32_t n)
+{
+	uint32_t res = size / n;
+	if (res * n != size)
+		res++;
+
+	return res;
+}
+
+void put_ext4(uint64_t off, void *buf, uint32_t size)
+{
+	uint64_t startblock;
+	uint64_t remainder;
+	unsigned char *temp_ptr = NULL;
+	unsigned 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, sec_buf);
+			temp_ptr = sec_buf;
+			memcpy((temp_ptr + remainder),
+			       (unsigned char *)buf, size);
+			fs->dev_desc->block_write(fs->dev_desc->dev,
+						  startblock, 1, 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, sec_buf);
+			temp_ptr = sec_buf;
+			memcpy(temp_ptr, buf, size);
+			fs->dev_desc->block_write(fs->dev_desc->dev,
+						  startblock, 1,
+						  (unsigned long *)sec_buf);
+		}
+	}
+}
+
+static int _get_new_inode_no(unsigned char *buffer)
+{
+	struct ext_filesystem *fs = get_fs();
+	unsigned char input;
+	int operand, status;
+	int count = 1;
+	int j = 0;
+
+	/* get the blocksize of the filesystem */
+	unsigned char *ptr = buffer;
+	while (*ptr == 255) {
+		ptr++;
+		count += 8;
+		if (count > 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;
+	int count = 0;
+	int 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 ext4fs_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;
+
+		*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;
+
+		*ptr = *ptr | operand;
+		return 0;
+	}
+}
+
+void ext4fs_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);
+	}
+}
+
+int ext4fs_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 * 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;
+
+	*ptr = *ptr | operand;
+
+	return 0;
+}
+
+void ext4fs_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 * 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);
+}
+
+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;
+	int sizeof_void_space;
+	int new_entry_byte_reqd;
+	short padding_factor = 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;
+
+	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;
+	}
+
+	return 0;
+}
+
+void ext4fs_update_parent_dentry(char *filename, int *p_ino, int file_type)
+{
+	unsigned int *zero_buffer = NULL;
+	char *root_first_block_buffer = NULL;
+	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;
+	int inodeno;
+	int status;
+	struct ext_filesystem *fs = get_fs();
+	/* directory entry */
+	struct ext2_dirent *dir;
+	char *ptr = NULL;
+	char *temp_dir = NULL;
+
+	zero_buffer = zalloc(fs->blksz);
+	if (!zero_buffer) {
+		printf("No Memory\n");
+		return;
+	}
+	root_first_block_buffer = zalloc(fs->blksz);
+	if (!root_first_block_buffer) {
+		free(zero_buffer);
+		printf("No Memory\n");
+		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 = ext4fs_devread(first_block_no_of_root
+				* fs->sect_perblk,
+				0, fs->blksz, root_first_block_buffer);
+	if (status == 0)
+		goto fail;
+
+	if (ext4fs_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:Allocate new block\n");
+
+				if (direct_blk_idx == INDIRECT_BLOCKS - 1) {
+					printf("Directory exceeds limit\n");
+					goto fail;
+				}
+				g_parent_inode->b.blocks.dir_blocks
+				    [direct_blk_idx] = ext4fs_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 (ext4fs_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 = ext4fs_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 (ext4fs_put_metadata(root_first_block_buffer,
+				first_block_no_of_root))
+		goto fail;
+
+ fail:
+	free(zero_buffer);
+	free(root_first_block_buffer);
+}
+
+static int search_dir(struct ext2_inode *parent_inode, char *dirname)
+{
+	int status;
+	int inodeno;
+	int totalbytes;
+	int templength;
+	int direct_blk_idx;
+	long int blknr;
+	int found = 0;
+	char *ptr = NULL;
+	unsigned char *block_buffer = NULL;
+	struct ext2_dirent *dir = NULL;
+	struct ext2_dirent *previous_dir = NULL;
+	struct ext_filesystem *fs = get_fs();
+
+	/* 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 = zalloc(fs->blksz);
+		if (!block_buffer)
+			goto fail;
+
+		status = ext4fs_devread(blknr * fs->sect_perblk,
+					0, fs->blksz, (char *)block_buffer);
+		if (status == 0)
+			goto fail;
+
+		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) {
+			free(block_buffer);
+			block_buffer = NULL;
+			return inodeno;
+		}
+
+		free(block_buffer);
+		block_buffer = NULL;
+	}
+
+ fail:
+	free(block_buffer);
+
+	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] = zalloc(strlen("/") + 1);
+	if (!arr[i])
+		return -ENOMEM;
+
+	arr[i++] = "/";
+
+	/* add each path entry after root */
+	while (token != NULL) {
+		arr[i] = zalloc(strlen(token) + 1);
+		if (!arr[i])
+			return -ENOMEM;
+		memcpy(arr[i++], token, strlen(token));
+		token = strtok(NULL, "/");
+	}
+	arr[i] = NULL;
+
+	return 0;
+}
+
+int ext4fs_iget(int inode_no, struct ext2_inode *inode)
+{
+	if (ext4fs_read_inode(ext4fs_root, inode_no, inode) == 0)
+		return -1;
+
+	return 0;
+}
+
+/*
+ * Function: ext4fs_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 ext4fs_get_parent_inode_num(const char *dirname, char *dname, int flags)
+{
+	int i;
+	int depth = 0;
+	int matched_inode_no;
+	int result_inode_no = -1;
+	char **ptr = NULL;
+	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;
+
+	if (*dirname != '/') {
+		printf("Please supply Absolute path\n");
+		return -1;
+	}
+
+	/* TODO: input validation make equivalent to linux */
+	depth_dirname = zalloc(strlen(dirname) + 1);
+	if (!depth_dirname)
+		return -ENOMEM;
+
+	memcpy(depth_dirname, dirname, strlen(dirname));
+	depth = find_dir_depth(depth_dirname);
+	parse_dirname = zalloc(strlen(dirname) + 1);
+	if (!parse_dirname)
+		goto fail;
+	memcpy(parse_dirname, dirname, strlen(dirname));
+
+	/* allocate memory for each directory level */
+	ptr = zalloc((depth) * sizeof(char *));
+	if (!ptr)
+		goto fail;
+	if (parse_path(ptr, parse_dirname))
+		goto fail;
+	parent_inode = zalloc(sizeof(struct ext2_inode));
+	if (!parent_inode)
+		goto fail;
+	first_inode = zalloc(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 (ext4fs_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) {
+		ext4fs_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:
+	free(depth_dirname);
+	free(parse_dirname);
+	free(ptr);
+	free(parent_inode);
+	free(first_inode);
+
+	return result_inode_no;
+}
+
+static int check_filename(char *filename, unsigned int blknr)
+{
+	unsigned int first_block_no_of_root;
+	int totalbytes = 0;
+	int templength = 0;
+	int status, inodeno;
+	int found = 0;
+	char *root_first_block_buffer = NULL;
+	char *root_first_block_addr = NULL;
+	struct ext2_dirent *dir = NULL;
+	struct ext2_dirent *previous_dir = NULL;
+	char *ptr = NULL;
+	struct ext_filesystem *fs = get_fs();
+
+	/* get the first block of root */
+	first_block_no_of_root = blknr;
+	root_first_block_buffer = zalloc(fs->blksz);
+	if (!root_first_block_buffer)
+		return -ENOMEM;
+	root_first_block_addr = root_first_block_buffer;
+	status = ext4fs_devread(first_block_no_of_root *
+				fs->sect_perblk, 0,
+				fs->blksz, root_first_block_buffer);
+	if (status == 0)
+		goto fail;
+
+	if (ext4fs_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
+		 */
+		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 (ext4fs_put_metadata(root_first_block_addr,
+					first_block_no_of_root))
+			goto fail;
+		return inodeno;
+	}
+ fail:
+	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;
+}
+
+long int ext4fs_get_new_blk_no(void)
+{
+	short i;
+	short status;
+	int remainder;
+	unsigned int bg_idx;
+	static int prev_bg_bitmap_index = -1;
+	unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
+	struct ext_filesystem *fs = get_fs();
+	char *journal_buffer = zalloc(fs->blksz);
+	char *zero_buffer = zalloc(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 = ext4fs_devread(gd[i].block_id *
+							fs->sect_perblk, 0,
+							fs->blksz,
+							journal_buffer);
+				if (status == 0)
+					goto fail;
+				if (ext4fs_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 / blk_per_grp;
+		} else {
+			bg_idx = fs->curr_blkno / blk_per_grp;
+			remainder = fs->curr_blkno % blk_per_grp;
+			if (!remainder)
+				bg_idx--;
+		}
+
+		/*
+		 * To skip completely filled block group bitmaps
+		 * Optimize the block allocation
+		 */
+		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 + blk_per_grp;
+			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 (ext4fs_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 = ext4fs_devread(gd[bg_idx].block_id
+						* fs->sect_perblk,
+						0, fs->blksz, journal_buffer);
+			if (status == 0)
+				goto fail;
+			if (ext4fs_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:
+	free(journal_buffer);
+	free(zero_buffer);
+
+	return fs->curr_blkno;
+ fail:
+	free(journal_buffer);
+	free(zero_buffer);
+
+	return -1;
+}
+
+int ext4fs_get_new_inode_no(void)
+{
+	short i;
+	short status;
+	unsigned int ibmap_idx;
+	static int prev_inode_bitmap_index = -1;
+	unsigned int inodes_per_grp = ext4fs_root->sblock.inodes_per_group;
+	struct ext_filesystem *fs = get_fs();
+	char *journal_buffer = zalloc(fs->blksz);
+	char *zero_buffer = zalloc(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 * inodes_per_grp);
+				fs->first_pass_ibmap++;
+				gd[i].free_inodes--;
+				gd[i].bg_itable_unused--;
+				fs->sb->free_inodes--;
+				status = ext4fs_devread(gd[i].inode_id *
+							fs->sect_perblk, 0,
+							fs->blksz,
+							journal_buffer);
+				if (status == 0)
+					goto fail;
+				if (ext4fs_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 / inodes_per_grp;
+		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 (ext4fs_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 = ext4fs_devread(gd[ibmap_idx].inode_id
+						* fs->sect_perblk,
+						0, fs->blksz, journal_buffer);
+			if (status == 0)
+				goto fail;
+			if (ext4fs_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:
+	free(journal_buffer);
+	free(zero_buffer);
+
+	return fs->curr_inode_no;
+ fail:
+	free(journal_buffer);
+	free(zero_buffer);
+
+	return -1;
+
+}
+
+static void alloc_single_indirect_block(struct ext2_inode *file_inode,
+					unsigned int *total_remaining_blocks,
+					unsigned int *no_blks_reqd)
+{
+	short i;
+	short status;
+	long int actual_block_no;
+	long int si_blockno;
+	/* si :single indirect */
+	unsigned int *si_buffer = NULL;
+	unsigned int *si_start_addr = NULL;
+	struct ext_filesystem *fs = get_fs();
+
+	if (*total_remaining_blocks != 0) {
+		si_buffer = zalloc(fs->blksz);
+		if (!si_buffer) {
+			printf("No Memory\n");
+			return;
+		}
+		si_start_addr = si_buffer;
+		si_blockno = ext4fs_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 = ext4fs_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 = ext4fs_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:
+	free(si_start_addr);
+}
+
+static void alloc_double_indirect_block(struct ext2_inode *file_inode,
+					unsigned int *total_remaining_blocks,
+					unsigned int *no_blks_reqd)
+{
+	short i;
+	short j;
+	short status;
+	long int actual_block_no;
+	/* di:double indirect */
+	long int di_blockno_parent;
+	long int 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 = ext4fs_get_new_blk_no();
+		if (di_blockno_parent == -1) {
+			printf("no block left to assign\n");
+			goto fail;
+		}
+		di_parent_buffer = zalloc(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 = ext4fs_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 = ext4fs_get_new_blk_no();
+			if (di_blockno_child == -1) {
+				printf("no block left to assign\n");
+				goto fail;
+			}
+			di_child_buff = zalloc(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 = ext4fs_devread(di_blockno_child *
+						fs->sect_perblk, 0,
+						fs->blksz,
+						(char *)di_child_buff);
+			memset(di_child_buff, '\0', fs->blksz);
+			/* filling of actual datablocks for each child */
+			for (j = 0; j < (fs->blksz / sizeof(int)); j++) {
+				actual_block_no = ext4fs_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);
+			free(di_child_buff_start);
+			di_child_buff_start = NULL;
+
+			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:
+	free(di_block_start_addr);
+}
+
+static void alloc_triple_indirect_block(struct ext2_inode *file_inode,
+					unsigned int *total_remaining_blocks,
+					unsigned int *no_blks_reqd)
+{
+	short i;
+	short j;
+	short k;
+	long int actual_block_no;
+	/* ti: Triple Indirect */
+	long int ti_gp_blockno;
+	long int ti_parent_blockno;
+	long int 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 = ext4fs_get_new_blk_no();
+		if (ti_gp_blockno == -1) {
+			printf("no block left to assign\n");
+			goto fail;
+		}
+		ti_gp_buff = zalloc(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 = ext4fs_get_new_blk_no();
+			if (ti_parent_blockno == -1) {
+				printf("no block left to assign\n");
+				goto fail;
+			}
+			ti_parent_buff = zalloc(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 = ext4fs_get_new_blk_no();
+				if (ti_child_blockno == -1) {
+					printf("no block left assign\n");
+					goto fail;
+				}
+				ti_child_buff = zalloc(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 actual datablocks for each child */
+				for (k = 0; k < (fs->blksz / sizeof(int));
+								k++) {
+					actual_block_no =
+					    ext4fs_get_new_blk_no();
+					if (actual_block_no == -1) {
+						printf("no block left\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);
+				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);
+			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.triple_indir_block = ti_gp_blockno;
+	}
+ fail:
+	free(ti_gp_buff_start_addr);
+}
+
+void ext4fs_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;
+
+	/* allocation of direct blocks */
+	for (i = 0; i < INDIRECT_BLOCKS; i++) {
+		direct_blockno = ext4fs_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;
+	}
+
+	alloc_single_indirect_block(file_inode, &total_remaining_blocks,
+				    &no_blks_reqd);
+	alloc_double_indirect_block(file_inode, &total_remaining_blocks,
+				    &no_blks_reqd);
+	alloc_triple_indirect_block(file_inode, &total_remaining_blocks,
+				    &no_blks_reqd);
+	*total_no_of_block += no_blks_reqd;
+}
+
+#endif
+
 static struct ext4_extent_header *ext4fs_get_extent_block
 	(struct ext2_data *data, char *buf,
 		struct ext4_extent_header *ext_block,
diff --git a/fs/ext4/ext4_common.h b/fs/ext4/ext4_common.h
index 182049d..0424798 100644
--- a/fs/ext4/ext4_common.h
+++ b/fs/ext4/ext4_common.h
@@ -14,6 +14,8 @@
  * GRUB  --  GRand Unified Bootloader
  * Copyright (C) 2003, 2004  Free Software Foundation, Inc.
  *
+ * ext4write : Based on generic ext4 protocol.
+ *
  * 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
@@ -35,6 +37,10 @@
 #include <ext4fs.h>
 #include <malloc.h>
 #include <asm/errno.h>
+#if defined(CONFIG_CMD_EXT4_WRITE)
+#include "ext4_journal.h"
+#include "crc16.h"
+#endif
 
 #define YES		1
 #define NO		0
@@ -60,4 +66,23 @@ int ext4fs_find_file(const char *path, struct ext2fs_node *rootnode,
 			struct ext2fs_node **foundnode, int expecttype);
 int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name,
 			struct ext2fs_node **fnode, int *ftype);
+
+#if defined(CONFIG_CMD_EXT4_WRITE)
+uint32_t ext4fs_div_roundup(uint32_t size, uint32_t n);
+int ext4fs_checksum_update(unsigned int i);
+int ext4fs_get_parent_inode_num(const char *dirname, char *dname, int flags);
+void ext4fs_update_parent_dentry(char *filename, int *p_ino, int file_type);
+long int ext4fs_get_new_blk_no(void);
+int ext4fs_get_new_inode_no(void);
+void ext4fs_reset_block_bmap(long int blockno, unsigned char *buffer,
+			     int index);
+int ext4fs_set_block_bmap(long int blockno, unsigned char *buffer, int index);
+int ext4fs_set_inode_bmap(int inode_no, unsigned char *buffer, int index);
+void ext4fs_reset_inode_bmap(int inode_no, unsigned char *buffer, int index);
+int ext4fs_iget(int inode_no, struct ext2_inode *inode);
+void ext4fs_allocate_blocks(struct ext2_inode *file_inode,
+			    unsigned int total_remaining_blocks,
+			    unsigned int *total_no_of_block);
+void put_ext4(uint64_t off, void *buf, uint32_t size);
+#endif
 #endif
diff --git a/fs/ext4/ext4_journal.c b/fs/ext4/ext4_journal.c
new file mode 100644
index 0000000..69cabd3
--- /dev/null
+++ b/fs/ext4/ext4_journal.c
@@ -0,0 +1,666 @@
+/*
+ * (C) Copyright 2011 - 2012 Samsung Electronics
+ * EXT4 filesystem implementation in Uboot by
+ * Uma Shankar <uma.shankar@samsung.com>
+ * Manjunatha C Achar <a.manjunatha@samsung.com>
+ *
+ * Journal data structures and headers for Journaling feature of ext4
+ * have been referred from JBD2 (Journaling Block device 2)
+ * implementation in Linux Kernel.
+ * Written by Stephen C. Tweedie <sct@redhat.com>
+ *
+ * Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <common.h>
+#include <ext4fs.h>
+#include <malloc.h>
+#include <ext_common.h>
+#include "ext4_common.h"
+
+static struct revoke_blk_list *revk_blk_list;
+static struct revoke_blk_list *prev_node;
+static int first_node = TRUE;
+
+int gindex;
+int gd_index;
+int jrnl_blk_idx;
+struct journal_log *journal_ptr[MAX_JOURNAL_ENTRIES];
+struct dirty_blocks *dirty_block_ptr[MAX_JOURNAL_ENTRIES];
+
+int ext4fs_init_journal(void)
+{
+	int i;
+	char *temp = NULL;
+	struct ext_filesystem *fs = get_fs();
+
+	/* init globals */
+	revk_blk_list = NULL;
+	prev_node = NULL;
+	gindex = 0;
+	gd_index = 0;
+	jrnl_blk_idx = 1;
+
+	for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
+		journal_ptr[i] = zalloc(sizeof(struct journal_log));
+		if (!journal_ptr[i])
+			goto fail;
+		dirty_block_ptr[i] = zalloc(sizeof(struct dirty_blocks));
+		if (!dirty_block_ptr[i])
+			goto fail;
+		journal_ptr[i]->buf = NULL;
+		journal_ptr[i]->blknr = -1;
+
+		dirty_block_ptr[i]->buf = NULL;
+		dirty_block_ptr[i]->blknr = -1;
+	}
+
+	if (fs->blksz == 4096) {
+		temp = zalloc(fs->blksz);
+		if (!temp)
+			goto fail;
+		journal_ptr[gindex]->buf = zalloc(fs->blksz);
+		if (!journal_ptr[gindex]->buf)
+			goto fail;
+		ext4fs_devread(0, 0, fs->blksz, temp);
+		memcpy(temp + SUPERBLOCK_SIZE, fs->sb, SUPERBLOCK_SIZE);
+		memcpy(journal_ptr[gindex]->buf, temp, fs->blksz);
+		journal_ptr[gindex++]->blknr = 0;
+		free(temp);
+	} else {
+		journal_ptr[gindex]->buf = zalloc(fs->blksz);
+		if (!journal_ptr[gindex]->buf)
+			goto fail;
+		memcpy(journal_ptr[gindex]->buf, fs->sb, SUPERBLOCK_SIZE);
+		journal_ptr[gindex++]->blknr = 1;
+	}
+
+	/* Check the file system state using journal super block */
+	if (ext4fs_check_journal_state(SCAN))
+		goto fail;
+	/* Check the file system state using journal super block */
+	if (ext4fs_check_journal_state(RECOVER))
+		goto fail;
+
+	return 0;
+ fail:
+	return -1;
+}
+
+void ext4fs_dump_metadata(void)
+{
+	struct ext_filesystem *fs = get_fs();
+	int i;
+	for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
+		if (dirty_block_ptr[i]->blknr == -1)
+			break;
+		put_ext4((uint64_t) (dirty_block_ptr[i]->blknr * fs->blksz),
+			 dirty_block_ptr[i]->buf, (uint32_t) fs->blksz);
+	}
+}
+
+void ext4fs_free_journal(void)
+{
+	int i;
+	for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
+		if (dirty_block_ptr[i]->blknr == -1)
+			break;
+		if (dirty_block_ptr[i]->buf)
+			free(dirty_block_ptr[i]->buf);
+	}
+
+	for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
+		if (journal_ptr[i]->blknr == -1)
+			break;
+		if (journal_ptr[i]->buf)
+			free(journal_ptr[i]->buf);
+	}
+
+	for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
+		if (journal_ptr[i])
+			free(journal_ptr[i]);
+		if (dirty_block_ptr[i])
+			free(dirty_block_ptr[i]);
+	}
+	gindex = 0;
+	gd_index = 0;
+	jrnl_blk_idx = 1;
+}
+
+int ext4fs_log_gdt(char *gd_table)
+{
+	struct ext_filesystem *fs = get_fs();
+	short i;
+	long int var = fs->gdtable_blkno;
+	for (i = 0; i < fs->no_blk_pergdt; i++) {
+		journal_ptr[gindex]->buf = zalloc(fs->blksz);
+		if (!journal_ptr[gindex]->buf)
+			return -ENOMEM;
+		memcpy(journal_ptr[gindex]->buf, gd_table, fs->blksz);
+		gd_table += fs->blksz;
+		journal_ptr[gindex++]->blknr = var++;
+	}
+
+	return 0;
+}
+
+/*
+ * This function stores the backup copy of meta data in RAM
+ * journal_buffer -- Buffer containing meta data
+ * blknr -- Block number on disk of the meta data buffer
+ */
+int ext4fs_log_journal(char *journal_buffer, long int blknr)
+{
+	struct ext_filesystem *fs = get_fs();
+	short i;
+
+	if (!journal_buffer) {
+		printf("Invalid input arguments %s\n", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
+		if (journal_ptr[i]->blknr == -1)
+			break;
+		if (journal_ptr[i]->blknr == blknr)
+			return 0;
+	}
+
+	journal_ptr[gindex]->buf = zalloc(fs->blksz);
+	if (!journal_ptr[gindex]->buf)
+		return -ENOMEM;
+
+	memcpy(journal_ptr[gindex]->buf, journal_buffer, fs->blksz);
+	journal_ptr[gindex++]->blknr = blknr;
+
+	return 0;
+}
+
+/*
+ * This function stores the modified meta data in RAM
+ * metadata_buffer -- Buffer containing meta data
+ * blknr -- Block number on disk of the meta data buffer
+ */
+int ext4fs_put_metadata(char *metadata_buffer, long int blknr)
+{
+	struct ext_filesystem *fs = get_fs();
+	if (!metadata_buffer) {
+		printf("Invalid input arguments %s\n", __func__);
+		return -EINVAL;
+	}
+	dirty_block_ptr[gd_index]->buf = zalloc(fs->blksz);
+	if (!dirty_block_ptr[gd_index]->buf)
+		return -ENOMEM;
+	memcpy(dirty_block_ptr[gd_index]->buf, metadata_buffer, fs->blksz);
+	dirty_block_ptr[gd_index++]->blknr = blknr;
+
+	return 0;
+}
+
+void print_revoke_blks(char *revk_blk)
+{
+	int offset;
+	int max;
+	long int blocknr;
+	struct journal_revoke_header_t *header;
+
+	if (revk_blk == NULL)
+		return;
+
+	header = (struct journal_revoke_header_t *)revk_blk;
+	offset = sizeof(struct journal_revoke_header_t);
+	max = be32_to_cpu(header->r_count);
+	printf("total bytes %d\n", max);
+
+	while (offset < max) {
+		blocknr = be32_to_cpu(*((long int *)(revk_blk + offset)));
+		printf("revoke blknr is %ld\n", blocknr);
+		offset += 4;
+	}
+}
+
+static struct revoke_blk_list *_get_node(void)
+{
+	struct revoke_blk_list *tmp_node;
+	tmp_node = zalloc(sizeof(struct revoke_blk_list));
+	if (tmp_node == NULL)
+		return NULL;
+	tmp_node->content = NULL;
+	tmp_node->next = NULL;
+
+	return tmp_node;
+}
+
+void ext4fs_push_revoke_blk(char *buffer)
+{
+	struct revoke_blk_list *node = NULL;
+	struct ext_filesystem *fs = get_fs();
+	if (buffer == NULL) {
+		printf("buffer ptr is NULL\n");
+		return;
+	}
+	node = _get_node();
+	if (!node) {
+		printf("_get_node: malloc failed\n");
+		return;
+	}
+
+	node->content = zalloc(fs->blksz);
+	if (node->content == NULL)
+		return;
+	memcpy(node->content, buffer, fs->blksz);
+
+	if (first_node == TRUE) {
+		revk_blk_list = node;
+		prev_node = node;
+		first_node = FALSE;
+	} else {
+		prev_node->next = node;
+		prev_node = node;
+	}
+}
+
+void ext4fs_free_revoke_blks(void)
+{
+	struct revoke_blk_list *tmp_node = revk_blk_list;
+	struct revoke_blk_list *next_node = NULL;
+
+	while (tmp_node != NULL) {
+		if (tmp_node->content)
+			free(tmp_node->content);
+		tmp_node = tmp_node->next;
+	}
+
+	tmp_node = revk_blk_list;
+	while (tmp_node != NULL) {
+		next_node = tmp_node->next;
+		free(tmp_node);
+		tmp_node = next_node;
+	}
+
+	revk_blk_list = NULL;
+	prev_node = NULL;
+	first_node = TRUE;
+}
+
+int check_blknr_for_revoke(long int blknr, int sequence_no)
+{
+	struct journal_revoke_header_t *header;
+	int offset;
+	int max;
+	long int blocknr;
+	char *revk_blk;
+	struct revoke_blk_list *tmp_revk_node = revk_blk_list;
+	while (tmp_revk_node != NULL) {
+		revk_blk = tmp_revk_node->content;
+
+		header = (struct journal_revoke_header_t *)revk_blk;
+		if (sequence_no <= be32_to_cpu(header->r_header.h_sequence)) {
+			offset = sizeof(struct journal_revoke_header_t);
+			max = be32_to_cpu(header->r_count);
+
+			while (offset < max) {
+				blocknr = be32_to_cpu(*((long int *)
+							(revk_blk + offset)));
+				if (blocknr == blknr)
+					goto found;
+				offset += 4;
+			}
+		}
+		tmp_revk_node = tmp_revk_node->next;
+	}
+
+	return -1;
+
+ found:
+	return 0;
+}
+
+/*
+ * This function parses the journal blocks and replays the
+ * suceessful transactions. A transaction is successfull
+ * if commit block is found for a descriptor block
+ * The tags in descriptor block contain the disk block
+ * numbers of the metadata  to be replayed
+ */
+void recover_transaction(int prev_desc_logical_no)
+{
+	struct ext2_inode inode_journal;
+	struct ext_filesystem *fs = get_fs();
+	struct journal_header_t *jdb;
+	long int blknr;
+	char *p_jdb;
+	int ofs, flags;
+	int i;
+	struct ext3_journal_block_tag *tag;
+	char *temp_buff = zalloc(fs->blksz);
+	char *metadata_buff = zalloc(fs->blksz);
+	if (!temp_buff || !metadata_buff)
+		goto fail;
+	i = prev_desc_logical_no;
+	ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
+			  (struct ext2_inode *)&inode_journal);
+	blknr = read_allocated_block((struct ext2_inode *)
+				     &inode_journal, i);
+	ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz, temp_buff);
+	p_jdb = (char *)temp_buff;
+	jdb = (struct journal_header_t *)temp_buff;
+	ofs = sizeof(struct journal_header_t);
+
+	do {
+		tag = (struct ext3_journal_block_tag *)&p_jdb[ofs];
+		ofs += sizeof(struct ext3_journal_block_tag);
+
+		if (ofs > fs->blksz)
+			break;
+
+		flags = be32_to_cpu(tag->flags);
+		if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID))
+			ofs += 16;
+
+		i++;
+		debug("\t\ttag %u\n", be32_to_cpu(tag->block));
+		if (revk_blk_list != NULL) {
+			if (check_blknr_for_revoke(be32_to_cpu(tag->block),
+						   be32_to_cpu(jdb->
+							       h_sequence)) ==
+			    0)
+				continue;
+		}
+		blknr = read_allocated_block(&inode_journal, i);
+		ext4fs_devread(blknr * fs->sect_perblk, 0,
+			       fs->blksz, metadata_buff);
+		put_ext4((uint64_t) (be32_to_cpu(tag->block) * fs->blksz),
+			 metadata_buff, (uint32_t) fs->blksz);
+	} while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG));
+ fail:
+	free(temp_buff);
+	free(metadata_buff);
+}
+
+void print_jrnl_status(int recovery_flag)
+{
+	if (recovery_flag == RECOVER)
+		printf("Journal Recovery Completed\n");
+	else
+		printf("Journal Scan Completed\n");
+}
+
+int ext4fs_check_journal_state(int recovery_flag)
+{
+	int i;
+	int DB_FOUND = NO;
+	long int blknr;
+	int transaction_state = TRANSACTION_COMPLETE;
+	int prev_desc_logical_no = 0;
+	int curr_desc_logical_no = 0;
+	int ofs, flags, block;
+	struct ext2_inode inode_journal;
+	struct journal_superblock_t *jsb = NULL;
+	struct journal_header_t *jdb = NULL;
+	char *p_jdb = NULL;
+	struct ext3_journal_block_tag *tag = NULL;
+	char *temp_buff = NULL;
+	char *temp_buff1 = NULL;
+	struct ext_filesystem *fs = get_fs();
+
+	temp_buff = zalloc(fs->blksz);
+	if (!temp_buff)
+		return -ENOMEM;
+	temp_buff1 = zalloc(fs->blksz);
+	if (!temp_buff1) {
+		free(temp_buff);
+		return -ENOMEM;
+	}
+
+	ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
+	blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK);
+	ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz, temp_buff);
+	jsb = (struct journal_superblock_t *)temp_buff;
+
+	if (fs->sb->feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) {
+		if (recovery_flag == RECOVER)
+			printf("Recovery required\n");
+	} else {
+		if (recovery_flag == RECOVER)
+			printf("File System is consistent\n");
+		goto end;
+	}
+
+	if (be32_to_cpu(jsb->s_start) == 0)
+		goto end;
+
+	if (!(jsb->s_feature_compat &
+	      cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM)))
+		jsb->s_feature_compat |=
+		    cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM);
+
+	i = be32_to_cpu(jsb->s_first);
+	while (1) {
+		block = be32_to_cpu(jsb->s_first);
+		blknr = read_allocated_block(&inode_journal, i);
+		memset(temp_buff1, '\0', fs->blksz);
+		ext4fs_devread(blknr * fs->sect_perblk,
+			       0, fs->blksz, temp_buff1);
+		jdb = (struct journal_header_t *)temp_buff1;
+
+		if (be32_to_cpu(jdb->h_blocktype) ==
+		    EXT3_JOURNAL_DESCRIPTOR_BLOCK) {
+			if (be32_to_cpu(jdb->h_sequence) !=
+			    be32_to_cpu(jsb->s_sequence)) {
+				print_jrnl_status(recovery_flag);
+				break;
+			}
+
+			curr_desc_logical_no = i;
+			if (transaction_state == TRANSACTION_COMPLETE)
+				transaction_state = TRANSACTION_RUNNING;
+			else
+				return -1;
+			p_jdb = (char *)temp_buff1;
+			ofs = sizeof(struct journal_header_t);
+			do {
+				tag = (struct ext3_journal_block_tag *)
+				    &p_jdb[ofs];
+				ofs += sizeof(struct ext3_journal_block_tag);
+				if (ofs > fs->blksz)
+					break;
+				flags = be32_to_cpu(tag->flags);
+				if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID))
+					ofs += 16;
+				i++;
+				debug("\t\ttag %u\n", be32_to_cpu(tag->block));
+			} while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG));
+			i++;
+			DB_FOUND = YES;
+		} else if (be32_to_cpu(jdb->h_blocktype) ==
+			   EXT3_JOURNAL_COMMIT_BLOCK) {
+			if ((be32_to_cpu(jdb->h_sequence) !=
+			     be32_to_cpu(jsb->s_sequence))
+			    || (DB_FOUND == NO)) {
+				print_jrnl_status(recovery_flag);
+				break;
+			}
+
+			if (transaction_state == TRANSACTION_RUNNING) {
+				transaction_state = TRANSACTION_COMPLETE;
+				i++;
+				jsb->s_sequence =
+				    cpu_to_be32(be32_to_cpu(jsb->s_sequence) +
+						1);
+			}
+			prev_desc_logical_no = curr_desc_logical_no;
+			recover_transaction(prev_desc_logical_no);
+			DB_FOUND = NO;
+		} else if (be32_to_cpu(jdb->h_blocktype) ==
+			   EXT3_JOURNAL_REVOKE_BLOCK) {
+			if (be32_to_cpu(jdb->h_sequence) !=
+			    be32_to_cpu(jsb->s_sequence)) {
+				print_jrnl_status(recovery_flag);
+				break;
+			}
+			if (recovery_flag == SCAN)
+				ext4fs_push_revoke_blk((char *)jdb);
+			i++;
+		} else {
+			debug("Else Case\n");
+			if (be32_to_cpu(jdb->h_sequence) !=
+			    be32_to_cpu(jsb->s_sequence)) {
+				print_jrnl_status(recovery_flag);
+				break;
+			}
+		}
+	}
+
+ end:
+	if (recovery_flag == RECOVER) {
+		jsb->s_start = cpu_to_be32(1);
+		jsb->s_sequence = cpu_to_be32(be32_to_cpu(jsb->s_sequence) + 1);
+		/* get the superblock */
+		ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE,
+			       (char *)fs->sb);
+		fs->sb->feature_incompat |= EXT3_FEATURE_INCOMPAT_RECOVER;
+
+		/* Update the super block */
+		put_ext4((uint64_t) (SUPERBLOCK_SIZE),
+			 (struct ext2_sblock *)fs->sb,
+			 (uint32_t) SUPERBLOCK_SIZE);
+		ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE,
+			       (char *)fs->sb);
+
+		blknr = read_allocated_block(&inode_journal,
+					     EXT2_JOURNAL_SUPERBLOCK);
+		put_ext4((uint64_t) (blknr * fs->blksz),
+			 (struct journal_superblock_t *)temp_buff,
+			 (uint32_t) fs->blksz);
+		ext4fs_free_revoke_blks();
+	}
+	free(temp_buff);
+	free(temp_buff1);
+
+	return 0;
+}
+
+static void update_descriptor_block(long int blknr)
+{
+	int i;
+	long int jsb_blknr;
+	struct journal_header_t jdb;
+	struct ext3_journal_block_tag tag;
+	struct ext2_inode inode_journal;
+	struct journal_superblock_t *jsb = NULL;
+	char *buf = NULL;
+	char *temp = NULL;
+	struct ext_filesystem *fs = get_fs();
+	char *temp_buff = zalloc(fs->blksz);
+	if (!temp_buff)
+		return;
+
+	ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
+	jsb_blknr = read_allocated_block(&inode_journal,
+					 EXT2_JOURNAL_SUPERBLOCK);
+	ext4fs_devread(jsb_blknr * fs->sect_perblk, 0, fs->blksz, temp_buff);
+	jsb = (struct journal_superblock_t *)temp_buff;
+
+	jdb.h_blocktype = cpu_to_be32(EXT3_JOURNAL_DESCRIPTOR_BLOCK);
+	jdb.h_magic = cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER);
+	jdb.h_sequence = jsb->s_sequence;
+	buf = zalloc(fs->blksz);
+	if (!buf) {
+		free(temp_buff);
+		return;
+	}
+	temp = buf;
+	memcpy(buf, &jdb, sizeof(struct journal_header_t));
+	temp += sizeof(struct journal_header_t);
+
+	for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
+		if (journal_ptr[i]->blknr == -1)
+			break;
+
+		tag.block = cpu_to_be32(journal_ptr[i]->blknr);
+		tag.flags = cpu_to_be32(EXT3_JOURNAL_FLAG_SAME_UUID);
+		memcpy(temp, &tag, sizeof(struct ext3_journal_block_tag));
+		temp = temp + sizeof(struct ext3_journal_block_tag);
+	}
+
+	tag.block = cpu_to_be32(journal_ptr[--i]->blknr);
+	tag.flags = cpu_to_be32(EXT3_JOURNAL_FLAG_LAST_TAG);
+	memcpy(temp - sizeof(struct ext3_journal_block_tag), &tag,
+	       sizeof(struct ext3_journal_block_tag));
+	put_ext4((uint64_t) (blknr * fs->blksz), buf, (uint32_t) fs->blksz);
+
+	free(temp_buff);
+	free(buf);
+}
+
+static void update_commit_block(long int blknr)
+{
+	struct journal_header_t jdb;
+	struct ext_filesystem *fs = get_fs();
+	char *buf = NULL;
+	struct ext2_inode inode_journal;
+	struct journal_superblock_t *jsb;
+	long int jsb_blknr;
+	char *temp_buff = zalloc(fs->blksz);
+	if (!temp_buff)
+		return;
+
+	ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
+	jsb_blknr = read_allocated_block(&inode_journal,
+					 EXT2_JOURNAL_SUPERBLOCK);
+	ext4fs_devread(jsb_blknr * fs->sect_perblk, 0, fs->blksz, temp_buff);
+	jsb = (struct journal_superblock_t *)temp_buff;
+
+	jdb.h_blocktype = cpu_to_be32(EXT3_JOURNAL_COMMIT_BLOCK);
+	jdb.h_magic = cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER);
+	jdb.h_sequence = jsb->s_sequence;
+	buf = zalloc(fs->blksz);
+	if (!buf) {
+		free(temp_buff);
+		return;
+	}
+	memcpy(buf, &jdb, sizeof(struct journal_header_t));
+	put_ext4((uint64_t) (blknr * fs->blksz), buf, (uint32_t) fs->blksz);
+
+	free(temp_buff);
+	free(buf);
+}
+
+void ext4fs_update_journal(void)
+{
+	struct ext2_inode inode_journal;
+	struct ext_filesystem *fs = get_fs();
+	long int blknr;
+	int i;
+	ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
+	blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++);
+	update_descriptor_block(blknr);
+	for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
+		if (journal_ptr[i]->blknr == -1)
+			break;
+		blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++);
+		put_ext4((uint64_t) (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..d973047
--- /dev/null
+++ b/fs/ext4/ext4_journal.h
@@ -0,0 +1,141 @@
+/*
+ * (C) Copyright 2011 - 2012 Samsung Electronics
+ * EXT4 filesystem implementation in Uboot by
+ * Uma Shankar <uma.shankar@samsung.com>
+ * Manjunatha C Achar <a.manjunatha@samsung.com>
+ *
+ * Journal data structures and headers for Journaling feature of ext4
+ * have been referred from JBD2 (Journaling Block device 2)
+ * implementation in Linux Kernel.
+ *
+ * Written by Stephen C. Tweedie <sct@redhat.com>
+ *
+ * Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __EXT4_JRNL__
+#define __EXT4_JRNL__
+
+#define EXT2_JOURNAL_INO		8	/* Journal inode */
+#define EXT2_JOURNAL_SUPERBLOCK	0	/* Journal  Superblock number */
+
+#define JBD2_FEATURE_COMPAT_CHECKSUM	0x00000001
+#define EXT3_JOURNAL_MAGIC_NUMBER	0xc03b3998U
+#define TRANSACTION_RUNNING		1
+#define TRANSACTION_COMPLETE		0
+#define EXT3_FEATURE_INCOMPAT_RECOVER	0x0004	/* Needs recovery */
+#define EXT3_JOURNAL_DESCRIPTOR_BLOCK	1
+#define EXT3_JOURNAL_COMMIT_BLOCK	2
+#define EXT3_JOURNAL_SUPERBLOCK_V1	3
+#define EXT3_JOURNAL_SUPERBLOCK_V2	4
+#define EXT3_JOURNAL_REVOKE_BLOCK	5
+#define EXT3_JOURNAL_FLAG_ESCAPE	1
+#define EXT3_JOURNAL_FLAG_SAME_UUID	2
+#define EXT3_JOURNAL_FLAG_DELETED	4
+#define EXT3_JOURNAL_FLAG_LAST_TAG	8
+
+/* Maximum entries in 1 journal transaction */
+#define MAX_JOURNAL_ENTRIES 100
+struct journal_log {
+	char *buf;
+	int blknr;
+};
+
+struct dirty_blocks {
+	char *buf;
+	int blknr;
+};
+
+/* Standard header for all descriptor blocks: */
+struct journal_header_t {
+	__u32 h_magic;
+	__u32 h_blocktype;
+	__u32 h_sequence;
+};
+
+/* The journal superblock.  All fields are in big-endian byte order. */
+struct journal_superblock_t {
+	/* 0x0000 */
+	struct journal_header_t s_header;
+
+	/* Static information describing the journal */
+	__u32 s_blocksize;	/* journal device blocksize */
+	__u32 s_maxlen;		/* total blocks in journal file */
+	__u32 s_first;		/* first block of log information */
+
+	/* Dynamic information describing the current state of the log */
+	__u32 s_sequence;	/* first commit ID expected in log */
+	__u32 s_start;		/* blocknr of start of log */
+
+	/* Error value, as set by journal_abort(). */
+	__s32 s_errno;
+
+	/* Remaining fields are only valid in a version-2 superblock */
+	__u32 s_feature_compat;	/* compatible feature set */
+	__u32 s_feature_incompat;	/* incompatible feature set */
+	__u32 s_feature_ro_compat;	/* readonly-compatible feature set */
+	/* 0x0030 */
+	__u8 s_uuid[16];	/* 128-bit uuid for journal */
+
+	/* 0x0040 */
+	__u32 s_nr_users;	/* Nr of filesystems sharing log */
+
+	__u32 s_dynsuper;	/* Blocknr of dynamic superblock copy */
+
+	/* 0x0048 */
+	__u32 s_max_transaction;	/* Limit of journal blocks per trans. */
+	__u32 s_max_trans_data;	/* Limit of data blocks per trans. */
+
+	/* 0x0050 */
+	__u32 s_padding[44];
+
+	/* 0x0100 */
+	__u8 s_users[16 * 48];	/* ids of all fs'es sharing the log */
+	/* 0x0400 */
+};
+
+struct ext3_journal_block_tag {
+	uint32_t block;
+	uint32_t flags;
+};
+
+struct journal_revoke_header_t {
+	struct journal_header_t r_header;
+	int r_count;		/* Count of bytes used in the block */
+};
+
+struct revoke_blk_list {
+	char *content;		/* revoke block itself */
+	struct revoke_blk_list *next;
+};
+
+extern struct ext2_data *ext4fs_root;
+
+int ext4fs_init_journal(void);
+int ext4fs_log_gdt(char *gd_table);
+int ext4fs_check_journal_state(int recovery_flag);
+int ext4fs_log_journal(char *journal_buffer, long int blknr);
+int ext4fs_put_metadata(char *metadata_buffer, long int blknr);
+void ext4fs_update_journal(void);
+void ext4fs_dump_metadata(void);
+void ext4fs_push_revoke_blk(char *buffer);
+void ext4fs_free_journal(void);
+void ext4fs_free_revoke_blks(void);
+#endif
diff --git a/fs/ext4/ext4fs.c b/fs/ext4/ext4fs.c
index 7933769..bc791bd 100644
--- a/fs/ext4/ext4fs.c
+++ b/fs/ext4/ext4fs.c
@@ -16,6 +16,8 @@
  * GRUB  --  GRand Unified Bootloader
  * Copyright (C) 2003, 2004  Free Software Foundation, Inc.
  *
+ * ext4write : Based on generic ext4 protocol.
+ *
  * 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
@@ -226,3 +228,961 @@ int ext4fs_read(char *buf, unsigned len)
 
 	return ext4fs_read_file(ext4fs_file, 0, len, buf);
 }
+
+#if defined(CONFIG_CMD_EXT4_WRITE)
+static void ext4fs_update(void)
+{
+	short i;
+	ext4fs_update_journal();
+	struct ext_filesystem *fs = get_fs();
+
+	/* update  super block */
+	put_ext4((uint64_t) (SUPERBLOCK_SIZE),
+		 (struct ext2_sblock *)fs->sb, (uint32_t) SUPERBLOCK_SIZE);
+
+	/* update block groups */
+	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], fs->blksz);
+	}
+
+	/* update inode table groups */
+	for (i = 0; i < fs->no_blkgrp; i++) {
+		put_ext4((uint64_t) (fs->gd[i].inode_id * fs->blksz),
+			 fs->inode_bmaps[i], fs->blksz);
+	}
+
+	/* update the block group descriptor table */
+	put_ext4((uint64_t) (fs->gdtable_blkno * fs->blksz),
+		 (struct ext2_block_group *)fs->gdtable,
+		 (fs->blksz * fs->no_blk_pergdt));
+
+	ext4fs_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 memory for gdtable */
+	fs->gdtable = zalloc(fs->blksz * fs->no_blk_pergdt);
+	if (!fs->gdtable)
+		return -ENOMEM;
+	/* read the group descriptor table */
+	status = ext4fs_devread(fs->gdtable_blkno * fs->sect_perblk, 0,
+				fs->blksz * fs->no_blk_pergdt, fs->gdtable);
+	if (status == 0)
+		goto fail;
+
+	if (ext4fs_log_gdt(fs->gdtable)) {
+		printf("Error in ext4fs_log_gdt\n");
+		return -1;
+	}
+
+	return 0;
+ fail:
+	free(fs->gdtable);
+	fs->gdtable = NULL;
+
+	return -1;
+}
+
+static void delete_single_indirect_block(struct ext2_inode *inode)
+{
+	struct ext2_block_group *gd = NULL;
+	static int prev_bg_bmap_idx = -1;
+	long int blknr;
+	int remainder;
+	int bg_idx;
+	int status;
+	unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
+	struct ext_filesystem *fs = get_fs();
+	char *journal_buffer = zalloc(fs->blksz);
+	if (!journal_buffer) {
+		printf("No memory\n");
+		return;
+	}
+	/* get  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 / blk_per_grp;
+		} else {
+			bg_idx = blknr / blk_per_grp;
+			remainder = blknr % blk_per_grp;
+			if (!remainder)
+				bg_idx--;
+		}
+		ext4fs_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_bmap_idx != bg_idx) {
+			status =
+			    ext4fs_devread(gd[bg_idx].block_id *
+					   fs->sect_perblk, 0, fs->blksz,
+					   journal_buffer);
+			if (status == 0)
+				goto fail;
+			if (ext4fs_log_journal
+			    (journal_buffer, gd[bg_idx].block_id))
+				goto fail;
+			prev_bg_bmap_idx = bg_idx;
+		}
+	}
+ fail:
+	free(journal_buffer);
+}
+
+static void delete_double_indirect_block(struct ext2_inode *inode)
+{
+	int i;
+	short status;
+	static int prev_bg_bmap_idx = -1;
+	long int blknr;
+	int remainder;
+	int bg_idx;
+	unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
+	unsigned int *di_buffer = NULL;
+	unsigned int *DIB_start_addr = NULL;
+	struct ext2_block_group *gd = NULL;
+	struct ext_filesystem *fs = get_fs();
+	char *journal_buffer = zalloc(fs->blksz);
+	if (!journal_buffer) {
+		printf("No memory\n");
+		return;
+	}
+	/* get the block group descriptor table */
+	gd = (struct ext2_block_group *)fs->gdtable;
+
+	if (inode->b.blocks.double_indir_block != 0) {
+		di_buffer = zalloc(fs->blksz);
+		if (!di_buffer) {
+			printf("No memory\n");
+			return;
+		}
+		DIB_start_addr = (unsigned int *)di_buffer;
+		blknr = inode->b.blocks.double_indir_block;
+		status = ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz,
+					(char *)di_buffer);
+		for (i = 0; i < fs->blksz / sizeof(int); i++) {
+			if (*di_buffer == 0)
+				break;
+
+			debug("DICB releasing %u\n", *di_buffer);
+			if (fs->blksz != 1024) {
+				bg_idx = (*di_buffer) / blk_per_grp;
+			} else {
+				bg_idx = (*di_buffer) / blk_per_grp;
+				remainder = (*di_buffer) % blk_per_grp;
+				if (!remainder)
+					bg_idx--;
+			}
+			ext4fs_reset_block_bmap(*di_buffer,
+						fs->blk_bmaps[bg_idx], bg_idx);
+			di_buffer++;
+			gd[bg_idx].free_blocks++;
+			fs->sb->free_blocks++;
+			/* journal backup */
+			if (prev_bg_bmap_idx != bg_idx) {
+				status = ext4fs_devread(gd[bg_idx].block_id
+							* fs->sect_perblk, 0,
+							fs->blksz,
+							journal_buffer);
+				if (status == 0)
+					goto fail;
+
+				if (ext4fs_log_journal(journal_buffer,
+						       gd[bg_idx].block_id))
+					goto fail;
+				prev_bg_bmap_idx = bg_idx;
+			}
+		}
+
+		/* removing the parent double indirect block */
+		blknr = inode->b.blocks.double_indir_block;
+		if (fs->blksz != 1024) {
+			bg_idx = blknr / blk_per_grp;
+		} else {
+			bg_idx = blknr / blk_per_grp;
+			remainder = blknr % blk_per_grp;
+			if (!remainder)
+				bg_idx--;
+		}
+		ext4fs_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_bmap_idx != bg_idx) {
+			memset(journal_buffer, '\0', fs->blksz);
+			status = ext4fs_devread(gd[bg_idx].block_id *
+						fs->sect_perblk, 0, fs->blksz,
+						journal_buffer);
+			if (status == 0)
+				goto fail;
+
+			if (ext4fs_log_journal(journal_buffer,
+					       gd[bg_idx].block_id))
+				goto fail;
+			prev_bg_bmap_idx = bg_idx;
+		}
+		debug("DIPB releasing %ld\n", blknr);
+	}
+ fail:
+	free(DIB_start_addr);
+	free(journal_buffer);
+}
+
+static void delete_triple_indirect_block(struct ext2_inode *inode)
+{
+	int i, j;
+	short status;
+	static int prev_bg_bmap_idx = -1;
+	long int blknr;
+	int remainder;
+	int bg_idx;
+	unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
+	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 = NULL;
+	struct ext_filesystem *fs = get_fs();
+	char *journal_buffer = zalloc(fs->blksz);
+	if (!journal_buffer) {
+		printf("No memory\n");
+		return;
+	}
+	/* get block group descriptor table */
+	gd = (struct ext2_block_group *)fs->gdtable;
+
+	if (inode->b.blocks.triple_indir_block != 0) {
+		tigp_buffer = zalloc(fs->blksz);
+		if (!tigp_buffer) {
+			printf("No memory\n");
+			return;
+		}
+		tib_start_addr = (unsigned int *)tigp_buffer;
+		blknr = inode->b.blocks.triple_indir_block;
+		status = ext4fs_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("tigp buffer releasing %u\n", *tigp_buffer);
+
+			tip_buffer = zalloc(fs->blksz);
+			if (!tip_buffer)
+				goto fail;
+			tipb_start_addr = (unsigned int *)tip_buffer;
+			status = ext4fs_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) / blk_per_grp;
+				} else {
+					bg_idx = (*tip_buffer) / blk_per_grp;
+
+					remainder = (*tip_buffer) % blk_per_grp;
+					if (!remainder)
+						bg_idx--;
+				}
+
+				ext4fs_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_bmap_idx != bg_idx) {
+					status =
+					    ext4fs_devread(gd[bg_idx].block_id *
+							   fs->sect_perblk, 0,
+							   fs->blksz,
+							   journal_buffer);
+					if (status == 0)
+						goto fail;
+
+					if (ext4fs_log_journal(journal_buffer,
+							       gd[bg_idx].
+							       block_id))
+						goto fail;
+					prev_bg_bmap_idx = bg_idx;
+				}
+			}
+			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) / blk_per_grp;
+			} else {
+				bg_idx = (*tigp_buffer) / blk_per_grp;
+
+				remainder = (*tigp_buffer) % blk_per_grp;
+				if (!remainder)
+					bg_idx--;
+			}
+			ext4fs_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_bmap_idx != bg_idx) {
+				memset(journal_buffer, '\0', fs->blksz);
+				status =
+				    ext4fs_devread(gd[bg_idx].block_id *
+						   fs->sect_perblk, 0,
+						   fs->blksz, journal_buffer);
+				if (status == 0)
+					goto fail;
+
+				if (ext4fs_log_journal(journal_buffer,
+						       gd[bg_idx].block_id))
+					goto fail;
+				prev_bg_bmap_idx = bg_idx;
+			}
+		}
+
+		/* removing the grand parent triple indirect block */
+		blknr = inode->b.blocks.triple_indir_block;
+		if (fs->blksz != 1024) {
+			bg_idx = blknr / blk_per_grp;
+		} else {
+			bg_idx = blknr / blk_per_grp;
+			remainder = blknr % blk_per_grp;
+			if (!remainder)
+				bg_idx--;
+		}
+		ext4fs_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_bmap_idx != bg_idx) {
+			memset(journal_buffer, '\0', fs->blksz);
+			status = ext4fs_devread(gd[bg_idx].block_id *
+						fs->sect_perblk, 0, fs->blksz,
+						journal_buffer);
+			if (status == 0)
+				goto fail;
+
+			if (ext4fs_log_journal(journal_buffer,
+					       gd[bg_idx].block_id))
+				goto fail;
+			prev_bg_bmap_idx = bg_idx;
+		}
+		debug("tigp buffer itself releasing %ld\n", blknr);
+	}
+ fail:
+	free(tib_start_addr);
+	free(tipb_start_addr);
+	free(journal_buffer);
+}
+
+static int ext4fs_delete_file(int inodeno)
+{
+	struct ext2_inode inode;
+	short status;
+	int i;
+	int remainder;
+	long int blknr;
+	int bg_idx;
+	int ibmap_idx;
+	char *read_buffer = NULL;
+	char *start_block_address = NULL;
+	unsigned int no_blocks;
+
+	static int prev_bg_bmap_idx = -1;
+	unsigned int inodes_per_block;
+	long int blkno;
+	unsigned int blkoff;
+	unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
+	unsigned int inode_per_grp = ext4fs_root->sblock.inodes_per_group;
+	struct ext2_inode *inode_buffer = NULL;
+	struct ext2_block_group *gd = NULL;
+	struct ext_filesystem *fs = get_fs();
+	char *journal_buffer = zalloc(fs->blksz);
+	if (!journal_buffer)
+		return -ENOMEM;
+	/* 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_FL) {
+		struct ext2fs_node *node_inode =
+		    zalloc(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 / blk_per_grp;
+			} else {
+				bg_idx = blknr / blk_per_grp;
+				remainder = blknr % blk_per_grp;
+				if (!remainder)
+					bg_idx--;
+			}
+			ext4fs_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_bmap_idx != bg_idx) {
+				status =
+				    ext4fs_devread(gd[bg_idx].block_id *
+						   fs->sect_perblk, 0,
+						   fs->blksz, journal_buffer);
+				if (status == 0)
+					goto fail;
+				if (ext4fs_log_journal(journal_buffer,
+						       gd[bg_idx].block_id))
+					goto fail;
+				prev_bg_bmap_idx = bg_idx;
+			}
+		}
+		if (node_inode) {
+			free(node_inode);
+			node_inode = NULL;
+		}
+	} else {
+
+		delete_single_indirect_block(&inode);
+		delete_double_indirect_block(&inode);
+		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 / blk_per_grp;
+			} else {
+				bg_idx = blknr / blk_per_grp;
+				remainder = blknr % blk_per_grp;
+				if (!remainder)
+					bg_idx--;
+			}
+			ext4fs_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_bmap_idx != bg_idx) {
+				memset(journal_buffer, '\0', fs->blksz);
+				status = ext4fs_devread(gd[bg_idx].block_id
+							* fs->sect_perblk,
+							0, fs->blksz,
+							journal_buffer);
+				if (status == 0)
+					goto fail;
+				if (ext4fs_log_journal(journal_buffer,
+						       gd[bg_idx].block_id))
+					goto fail;
+				prev_bg_bmap_idx = bg_idx;
+			}
+		}
+	}
+
+	/* from the inode no to blockno */
+	inodes_per_block = fs->blksz / fs->inodesz;
+	ibmap_idx = inodeno / inode_per_grp;
+
+	/* get the block no */
+	inodeno--;
+	blkno = __le32_to_cpu(gd[ibmap_idx].inode_table_id) +
+	    (inodeno % __le32_to_cpu(inode_per_grp)) / 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 = zalloc(fs->blksz);
+	if (!read_buffer)
+		goto fail;
+	start_block_address = read_buffer;
+	status = ext4fs_devread(blkno * fs->sect_perblk,
+				0, fs->blksz, read_buffer);
+	if (status == 0)
+		goto fail;
+
+	if (ext4fs_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 (ext4fs_put_metadata(start_block_address, blkno))
+		goto fail;
+
+	/* update the respective inode bitmaps */
+	inodeno++;
+	ext4fs_reset_inode_bmap(inodeno, fs->inode_bmaps[ibmap_idx], ibmap_idx);
+	gd[ibmap_idx].free_inodes++;
+	fs->sb->free_inodes++;
+	/* journal backup */
+	memset(journal_buffer, '\0', fs->blksz);
+	status = ext4fs_devread(gd[ibmap_idx].inode_id *
+				fs->sect_perblk, 0, fs->blksz, journal_buffer);
+	if (status == 0)
+		goto fail;
+	if (ext4fs_log_journal(journal_buffer, gd[ibmap_idx].inode_id))
+		goto fail;
+
+	ext4fs_update();
+	ext4fs_deinit();
+
+	if (ext4fs_init() != 0) {
+		printf("error in File System init\n");
+		goto fail;
+	}
+
+	free(start_block_address);
+	free(journal_buffer);
+
+	return 0;
+ fail:
+	free(start_block_address);
+	free(journal_buffer);
+
+	return -1;
+}
+
+int ext4fs_init(void)
+{
+	short status;
+	int i;
+	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;
+
+	/* get the superblock */
+	fs->sb = zalloc(SUPERBLOCK_SIZE);
+	if (!fs->sb)
+		return -ENOMEM;
+	if (!ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE,
+			    (char *)fs->sb))
+		goto fail;
+
+	/* init journal */
+	if (ext4fs_init_journal())
+		goto fail;
+
+	/* get total no of blockgroups */
+	fs->no_blkgrp = (uint32_t) ext4fs_div_roundup
+	    ((ext4fs_root->sblock.total_blocks -
+	      ext4fs_root->sblock.first_data_block),
+	     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("Error in getting the block group descriptor table\n");
+		goto fail;
+	}
+	fs->gd = (struct ext2_block_group *)fs->gdtable;
+
+	/* load all the available bitmap block of the partition */
+	fs->blk_bmaps = zalloc(fs->no_blkgrp * sizeof(char *));
+	if (!fs->blk_bmaps)
+		goto fail;
+	for (i = 0; i < fs->no_blkgrp; i++) {
+		fs->blk_bmaps[i] = zalloc(fs->blksz);
+		if (!fs->blk_bmaps[i])
+			goto fail;
+	}
+
+	for (i = 0; i < fs->no_blkgrp; i++) {
+		status =
+		    ext4fs_devread(fs->gd[i].block_id * fs->sect_perblk, 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 = zalloc(fs->no_blkgrp * sizeof(unsigned char *));
+	if (!fs->inode_bmaps)
+		goto fail;
+	for (i = 0; i < fs->no_blkgrp; i++) {
+		fs->inode_bmaps[i] = zalloc(fs->blksz);
+		if (!fs->inode_bmaps[i])
+			goto fail;
+	}
+
+	for (i = 0; i < fs->no_blkgrp; i++) {
+		status = ext4fs_devread(fs->gd[i].inode_id * fs->sect_perblk,
+					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 = zalloc(fs->blksz);
+	if (temp_buff) {
+		ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
+				  &inode_journal);
+		blknr = read_allocated_block(&inode_journal,
+					     EXT2_JOURNAL_SUPERBLOCK);
+		ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz,
+			       temp_buff);
+		jsb = (struct journal_superblock_t *)temp_buff;
+		jsb->s_start = cpu_to_be32(0);
+		put_ext4((uint64_t) (blknr * fs->blksz),
+			 (struct journal_superblock_t *)temp_buff, fs->blksz);
+		free(temp_buff);
+	}
+	ext4fs_free_journal();
+
+	/* get the superblock */
+	ext4fs_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);
+	free(fs->sb);
+	fs->sb = NULL;
+
+	if (fs->blk_bmaps) {
+		for (i = 0; i < fs->no_blkgrp; 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++) {
+			free(fs->inode_bmaps[i]);
+			fs->inode_bmaps[i] = NULL;
+		}
+		free(fs->inode_bmaps);
+		fs->inode_bmaps = NULL;
+	}
+
+	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;
+}
+
+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(const char *fname, unsigned char *buffer,
+					unsigned long sizebytes)
+{
+	int ret = 0;
+	struct ext2_inode *file_inode = NULL;
+	unsigned char *inode_buffer = NULL;
+	int parent_inodeno;
+	int inodeno;
+	time_t timestamp = 0;
+
+	uint64_t bytes_reqd_for_file;
+	unsigned int blks_reqd_for_file;
+	unsigned int blocks_remaining;
+	int existing_file_inodeno;
+	char filename[256];
+
+	char *temp_ptr = NULL;
+	long int itable_blkno;
+	long int parent_itable_blkno;
+	long int blkoff;
+	struct ext2_sblock *sblock = &(ext4fs_root->sblock);
+	unsigned int inodes_per_block;
+	unsigned int ibmap_idx;
+	struct ext_filesystem *fs = get_fs();
+	g_parent_inode = zalloc(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 = ext4fs_get_parent_inode_num(fname, filename, F_FILE);
+	if (parent_inodeno == -1)
+		goto fail;
+	if (ext4fs_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 */
+	bytes_reqd_for_file = sizebytes;
+	blks_reqd_for_file = bytes_reqd_for_file / fs->blksz;
+	if (bytes_reqd_for_file % fs->blksz != 0) {
+		blks_reqd_for_file++;
+		debug("total bytes for a file %u\n", blks_reqd_for_file);
+	}
+	blocks_remaining = blks_reqd_for_file;
+	/* test for available space in partition */
+	if (fs->sb->free_blocks < blks_reqd_for_file) {
+		printf("Not enough space on partition !!!\n");
+		goto fail;
+	}
+
+	ext4fs_update_parent_dentry(filename, &inodeno, FILETYPE_REG);
+	/* prepare file inode */
+	inode_buffer = zalloc(fs->inodesz);
+	if (!inode_buffer)
+		goto fail;
+	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 */
+	ext4fs_allocate_blocks(file_inode, blocks_remaining,
+			       &blks_reqd_for_file);
+	file_inode->blockcnt = (blks_reqd_for_file * fs->blksz) / SECTOR_SIZE;
+
+	temp_ptr = zalloc(fs->blksz);
+	if (!temp_ptr)
+		goto fail;
+	ibmap_idx = inodeno / ext4fs_root->sblock.inodes_per_group;
+	inodeno--;
+	itable_blkno = __le32_to_cpu(fs->gd[ibmap_idx].inode_table_id) +
+	    (inodeno % __le32_to_cpu(sblock->inodes_per_group)) /
+	    inodes_per_block;
+	blkoff = (inodeno % inodes_per_block) * fs->inodesz;
+	ext4fs_devread(itable_blkno * fs->sect_perblk, 0, fs->blksz, temp_ptr);
+	if (ext4fs_log_journal(temp_ptr, itable_blkno))
+		goto fail;
+
+	memcpy(temp_ptr + blkoff, inode_buffer, fs->inodesz);
+	if (ext4fs_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;
+	}
+	ibmap_idx = parent_inodeno / ext4fs_root->sblock.inodes_per_group;
+	parent_inodeno--;
+	parent_itable_blkno = __le32_to_cpu(fs->gd[ibmap_idx].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);
+		ext4fs_devread(parent_itable_blkno * fs->sect_perblk,
+			       0, fs->blksz, temp_ptr);
+		if (ext4fs_log_journal(temp_ptr, parent_itable_blkno))
+			goto fail;
+
+		memcpy(temp_ptr + blkoff, g_parent_inode,
+		       sizeof(struct ext2_inode));
+		if (ext4fs_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 (ext4fs_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;
+	free(inode_buffer);
+	free(g_parent_inode);
+	g_parent_inode = NULL;
+
+	return 0;
+ fail:
+	ext4fs_deinit();
+	free(inode_buffer);
+	free(g_parent_inode);
+	g_parent_inode = NULL;
+
+	return -1;
+}
+#endif
diff --git a/include/ext4fs.h b/include/ext4fs.h
index 55f9ccc..a56e302 100644
--- a/include/ext4fs.h
+++ b/include/ext4fs.h
@@ -117,6 +117,18 @@ extern block_dev_desc_t *ext4_dev_desc;
 extern struct ext2_data *ext4fs_root;
 extern struct ext2fs_node *ext4fs_file;
 
+#if defined(CONFIG_CMD_EXT4_WRITE)
+extern struct ext2_inode *g_parent_inode;
+extern int gd_index;
+extern int gindex;
+
+int ext4fs_init(void);
+void ext4fs_deinit(void);
+int ext4fs_filename_check(char *filename);
+int ext4fs_write(const char *fname, unsigned char *buffer,
+				unsigned long sizebytes);
+#endif
+
 struct ext_filesystem *get_fs(void);
 int init_fs(block_dev_desc_t *dev_desc);
 void deinit_fs(block_dev_desc_t *dev_desc);
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [U-Boot] [PATCH V4 2/2] ext4fs write support
  2012-01-09 17:56   ` [U-Boot] [PATCH V4 " uma.shankar at samsung.com
@ 2012-01-16  0:03     ` Mike Frysinger
  2012-01-16  7:58       ` Wolfgang Denk
  2012-05-25 15:52     ` [U-Boot] [PATCH V5 " Uma Shankar
  1 sibling, 1 reply; 14+ messages in thread
From: Mike Frysinger @ 2012-01-16  0:03 UTC (permalink / raw)
  To: u-boot

On Monday 09 January 2012 12:56:16 uma.shankar at samsung.com wrote:
> --- a/common/Makefile
> +++ b/common/Makefile
>
> +ifndef CONFIG_CMD_EXT4
> +COBJS-$(CONFIG_CMD_EXT4_WRITE) += cmd_ext4.o
> +endif

the CONFIG_CMD_EXT4 check is not necessary.  if someone tries to enable 
CONFIG_CMD_EXT4_WRITE but not CONFIG_CMD_EXT4, that's their fault.
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20120115/b04fd1e9/attachment.pgp>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [U-Boot] [PATCH V4 2/2] ext4fs write support
  2012-01-16  0:03     ` Mike Frysinger
@ 2012-01-16  7:58       ` Wolfgang Denk
  2012-01-16 10:06         ` Mike Frysinger
  0 siblings, 1 reply; 14+ messages in thread
From: Wolfgang Denk @ 2012-01-16  7:58 UTC (permalink / raw)
  To: u-boot

Dear Mike Frysinger,

In message <201201151903.09599.vapier@gentoo.org> you wrote:
>
> > +ifndef CONFIG_CMD_EXT4
> > +COBJS-$(CONFIG_CMD_EXT4_WRITE) += cmd_ext4.o
> > +endif
> 
> the CONFIG_CMD_EXT4 check is not necessary.  if someone tries to enable 
> CONFIG_CMD_EXT4_WRITE but not CONFIG_CMD_EXT4, that's their fault.

we can try to be a bit user-friendly at least and throw a compile time
error message.

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 at denx.de
"Virtual" means never knowing where your next byte is coming from.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [U-Boot] [PATCH V4 2/2] ext4fs write support
  2012-01-16  7:58       ` Wolfgang Denk
@ 2012-01-16 10:06         ` Mike Frysinger
  0 siblings, 0 replies; 14+ messages in thread
From: Mike Frysinger @ 2012-01-16 10:06 UTC (permalink / raw)
  To: u-boot

On Monday 16 January 2012 02:58:20 Wolfgang Denk wrote:
> Mike Frysinger wrote:
> > > +ifndef CONFIG_CMD_EXT4
> > > +COBJS-$(CONFIG_CMD_EXT4_WRITE) += cmd_ext4.o
> > > +endif
> > 
> > the CONFIG_CMD_EXT4 check is not necessary.  if someone tries to enable
> > CONFIG_CMD_EXT4_WRITE but not CONFIG_CMD_EXT4, that's their fault.
> 
> we can try to be a bit user-friendly at least and throw a compile time
> error message.

i'm fine with that.  i just don't think this checking belongs in the Makefiles.
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20120116/5c48c87c/attachment.pgp>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [U-Boot] [PATCH V5 2/2] ext4fs write support
  2012-01-09 17:56   ` [U-Boot] [PATCH V4 " uma.shankar at samsung.com
  2012-01-16  0:03     ` Mike Frysinger
@ 2012-05-25 15:52     ` Uma Shankar
  2012-08-09 21:50       ` Wolfgang Denk
  1 sibling, 1 reply; 14+ messages in thread
From: Uma Shankar @ 2012-05-25 15:52 UTC (permalink / raw)
  To: u-boot


Signed-off-by: Uma Shankar <uma.shankar@samsung.com>
Signed-off-by: Manjunatha C Achar <a.manjunatha@samsung.com>
Signed-off-by: Iqbal Shareef <iqbal.ams@samsung.com>
Signed-off-by: Hakgoo Lee <goodguy.lee@samsung.com>
---
Changes for v4:
        - Redesigned ext2, ext4 command interface
        - Removed ext2 folder from fs/
        - Memory Leak issue handled

Changes for v3:
        - Copyright has been updated in respective files
        - ext4fs has been made independant of ext2fs.c
        - Fixed API namespace
        - Removed endianness conversion API, used uboot defined API
          for the same
        - Fixed coding style issues
        - Moved README.ext4 file into doc folder

Changes for v2:
        - Code cleanup, changed comment style
        - camel case removed, resolved code alignment issues
        - memory allocation logic changed, removed busybox logic
        - Modified ext4 load to remove grub dependency (GPLv3)
        - Introduced new Config for ext4 write

Changes for v1:
        - Removed checkpatch warnings and errors
        - Moved common API's of ext2 and ext4 to one generic header file


---
 common/cmd_ext4.c      |  141 +++++
 doc/README.ext4        |   46 ++
 fs/ext4/Makefile       |    1 +
 fs/ext4/crc16.c        |   62 +++
 fs/ext4/crc16.h        |   16 +
 fs/ext4/ext4_common.c  | 1353 ++++++++++++++++++++++++++++++++++++++++++++++++
 fs/ext4/ext4_common.h  |   25 +
 fs/ext4/ext4_journal.c |  667 ++++++++++++++++++++++++
 fs/ext4/ext4_journal.h |  141 +++++
 fs/ext4/ext4fs.c       |  961 ++++++++++++++++++++++++++++++++++
 include/ext4fs.h       |   12 +
 include/ext_common.h   |    2 +
 12 files changed, 3427 insertions(+), 0 deletions(-)
 create mode 100644 doc/README.ext4
 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 3298fee..77094c4 100644
--- a/common/cmd_ext4.c
+++ b/common/cmd_ext4.c
@@ -62,6 +62,10 @@
 
 uint64_t total_sector;
 uint64_t part_offset;
+#if defined(CONFIG_CMD_EXT4_WRITE)
+static uint64_t part_size;
+static uint16_t cur_part = 1;
+#endif
 
 #define DOS_PART_MAGIC_OFFSET		0x1fe
 #define DOS_FS_TYPE_OFFSET		0x36
@@ -84,6 +88,143 @@ int do_ext4_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
 	return 0;
 }
 
+#if defined(CONFIG_CMD_EXT4_WRITE)
+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_write(cmd_tbl_t *cmdtp, int flag, int argc,
+				char *const argv[])
+{
+	const char *filename = "/";
+	int part_length;
+	unsigned long part = 1;
+	int dev;
+	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;
+		}
+		part = simple_strtoul(++ep, NULL, 16);
+	}
+
+	/* get the filename */
+	filename = argv[3];
+
+	/* get the address in hexadecimal format (string to int) */
+	ram_address = simple_strtoul(argv[4], NULL, 16);
+
+	/* get the filesize in base 10 format */
+	file_size = simple_strtoul(argv[5], NULL, 10);
+
+	/* set the device as block device */
+	part_length = ext4fs_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(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");
+
+#endif
+
 U_BOOT_CMD(ext4ls, 4, 1, do_ext4_ls,
 	   "list files in a directory (default /)",
 	   "<interface> <dev[:part]> [directory]\n"
diff --git a/doc/README.ext4 b/doc/README.ext4
new file mode 100644
index 0000000..b3ea8b7
--- /dev/null
+++ b/doc/README.ext4
@@ -0,0 +1,46 @@
+This patch series adds support for ext4 ls,load and write features in uboot
+Journaling is supported for write feature.
+
+To Enable ext2 ls and load commands, modify the board specific config file with
+#define CONFIG_CMD_EXT2
+
+To Enable ext4 ls and load commands, modify the board specific config file with
+#define CONFIG_CMD_EXT4
+
+To enable ext4 write command, modify the board specific config file with
+#define CONFIG_CMD_EXT4
+#define CONFIG_CMD_EXT4_WRITE
+
+Steps to test:
+
+1. After applying the patch, ext4 specific commands can be seen
+   in the boot loader prompt using
+        UBOOT #help
+
+        ext4load- load binary file from a Ext4 file system
+        ext4ls  - list files in a directory (default /)
+        ext4write- create a file in ext4 formatted partition
+
+2. To list the files in ext4 formatted partition, execute
+        ext4ls <interface> <dev[:part]> [directory]
+        For example:
+        UBOOT #ext4ls mmc 0:5 /usr/lib
+
+3. To read and load a file from an ext4 formatted partition to RAM, execute
+        ext4load <interface> <dev[:part]> [addr] [filename] [bytes]
+        For example:
+        UBOOT #ext4load mmc 2:2 0x30007fc0 uImage
+
+4. To write a file to a ext4 formatted partition.
+        a) First load a file to RAM at a particular address for example 0x30007fc0.
+        Now execute ext4write command
+        ext4write <interface> <dev[:part]> [filename] [Address] [sizebytes]
+        For example:
+        UBOOT #ext4write mmc 2:2 /boot/uImage 0x30007fc0 6183120
+        (here 6183120 is the size of the file to be written)
+        Note: Absolute path is required for the file to be written
+
+References :
+	-- ext4 implementation in Linux Kernel
+	-- Uboot existing ext2 load and ls implementation
+	-- Journaling block device JBD2 implementation in linux Kernel
diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile
index 7b7fcbd..82cd9ae 100644
--- a/fs/ext4/Makefile
+++ b/fs/ext4/Makefile
@@ -34,6 +34,7 @@ COBJS-$(CONFIG_CMD_EXT4) := ext4fs.o ext4_common.o dev.o
 ifndef CONFIG_CMD_EXT4
 COBJS-$(CONFIG_CMD_EXT2) := ext4fs.o ext4_common.o dev.o
 endif
+COBJS-$(CONFIG_CMD_EXT4_WRITE) += 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@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 2ddbb50..083e45e 100644
--- a/fs/ext4/ext4_common.c
+++ b/fs/ext4/ext4_common.c
@@ -14,6 +14,8 @@
  * GRUB  --  GRand Unified Bootloader
  * Copyright (C) 2003, 2004  Free Software Foundation, Inc.
  *
+ * ext4write : Based on generic ext4 protocol.
+ *
  * 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
@@ -54,6 +56,1357 @@ int ext4fs_indir3_blkno = -1;
 struct ext2_inode *g_parent_inode;
 static int symlinknest;
 
+#if defined(CONFIG_CMD_EXT4_WRITE)
+uint32_t ext4fs_div_roundup(uint32_t size, uint32_t n)
+{
+	uint32_t res = size / n;
+	if (res * n != size)
+		res++;
+
+	return res;
+}
+
+void put_ext4(uint64_t off, void *buf, uint32_t size)
+{
+	uint64_t startblock;
+	uint64_t remainder;
+	unsigned char *temp_ptr = NULL;
+	unsigned 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, sec_buf);
+			temp_ptr = sec_buf;
+			memcpy((temp_ptr + remainder),
+			       (unsigned char *)buf, size);
+			fs->dev_desc->block_write(fs->dev_desc->dev,
+						  startblock, 1, 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, sec_buf);
+			temp_ptr = sec_buf;
+			memcpy(temp_ptr, buf, size);
+			fs->dev_desc->block_write(fs->dev_desc->dev,
+						  startblock, 1,
+						  (unsigned long *)sec_buf);
+		}
+	}
+}
+
+static int _get_new_inode_no(unsigned char *buffer)
+{
+	struct ext_filesystem *fs = get_fs();
+	unsigned char input;
+	int operand, status;
+	int count = 1;
+	int j = 0;
+
+	/* get the blocksize of the filesystem */
+	unsigned char *ptr = buffer;
+	while (*ptr == 255) {
+		ptr++;
+		count += 8;
+		if (count > 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;
+	int count = 0;
+	int 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 ext4fs_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;
+
+		*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;
+
+		*ptr = *ptr | operand;
+		return 0;
+	}
+}
+
+void ext4fs_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);
+	}
+}
+
+int ext4fs_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 * 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;
+
+	*ptr = *ptr | operand;
+
+	return 0;
+}
+
+void ext4fs_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 * 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);
+}
+
+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;
+	int sizeof_void_space;
+	int new_entry_byte_reqd;
+	short padding_factor = 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;
+
+	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;
+	}
+
+	return 0;
+}
+
+void ext4fs_update_parent_dentry(char *filename, int *p_ino, int file_type)
+{
+	unsigned int *zero_buffer = NULL;
+	char *root_first_block_buffer = NULL;
+	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;
+	int inodeno;
+	int status;
+	struct ext_filesystem *fs = get_fs();
+	/* directory entry */
+	struct ext2_dirent *dir;
+	char *ptr = NULL;
+	char *temp_dir = NULL;
+
+	zero_buffer = zalloc(fs->blksz);
+	if (!zero_buffer) {
+		printf("No Memory\n");
+		return;
+	}
+	root_first_block_buffer = zalloc(fs->blksz);
+	if (!root_first_block_buffer) {
+		free(zero_buffer);
+		printf("No Memory\n");
+		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 = ext4fs_devread(first_block_no_of_root
+				* fs->sect_perblk,
+				0, fs->blksz, root_first_block_buffer);
+	if (status == 0)
+		goto fail;
+
+	if (ext4fs_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:Allocate new block\n");
+
+				if (direct_blk_idx == INDIRECT_BLOCKS - 1) {
+					printf("Directory exceeds limit\n");
+					goto fail;
+				}
+				g_parent_inode->b.blocks.dir_blocks
+				    [direct_blk_idx] = ext4fs_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 (ext4fs_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 = ext4fs_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 (ext4fs_put_metadata(root_first_block_buffer,
+				first_block_no_of_root))
+		goto fail;
+
+fail:
+	free(zero_buffer);
+	free(root_first_block_buffer);
+}
+
+static int search_dir(struct ext2_inode *parent_inode, char *dirname)
+{
+	int status;
+	int inodeno;
+	int totalbytes;
+	int templength;
+	int direct_blk_idx;
+	long int blknr;
+	int found = 0;
+	char *ptr = NULL;
+	unsigned char *block_buffer = NULL;
+	struct ext2_dirent *dir = NULL;
+	struct ext2_dirent *previous_dir = NULL;
+	struct ext_filesystem *fs = get_fs();
+
+	/* 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 = zalloc(fs->blksz);
+		if (!block_buffer)
+			goto fail;
+
+		status = ext4fs_devread(blknr * fs->sect_perblk,
+					0, fs->blksz, (char *)block_buffer);
+		if (status == 0)
+			goto fail;
+
+		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) {
+			free(block_buffer);
+			block_buffer = NULL;
+			return inodeno;
+		}
+
+		free(block_buffer);
+		block_buffer = NULL;
+	}
+
+fail:
+	free(block_buffer);
+
+	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] = zalloc(strlen("/") + 1);
+	if (!arr[i])
+		return -ENOMEM;
+
+	arr[i++] = "/";
+
+	/* add each path entry after root */
+	while (token != NULL) {
+		arr[i] = zalloc(strlen(token) + 1);
+		if (!arr[i])
+			return -ENOMEM;
+		memcpy(arr[i++], token, strlen(token));
+		token = strtok(NULL, "/");
+	}
+	arr[i] = NULL;
+
+	return 0;
+}
+
+int ext4fs_iget(int inode_no, struct ext2_inode *inode)
+{
+	if (ext4fs_read_inode(ext4fs_root, inode_no, inode) == 0)
+		return -1;
+
+	return 0;
+}
+
+/*
+ * Function: ext4fs_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 ext4fs_get_parent_inode_num(const char *dirname, char *dname, int flags)
+{
+	int i;
+	int depth = 0;
+	int matched_inode_no;
+	int result_inode_no = -1;
+	char **ptr = NULL;
+	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;
+
+	if (*dirname != '/') {
+		printf("Please supply Absolute path\n");
+		return -1;
+	}
+
+	/* TODO: input validation make equivalent to linux */
+	depth_dirname = zalloc(strlen(dirname) + 1);
+	if (!depth_dirname)
+		return -ENOMEM;
+
+	memcpy(depth_dirname, dirname, strlen(dirname));
+	depth = find_dir_depth(depth_dirname);
+	parse_dirname = zalloc(strlen(dirname) + 1);
+	if (!parse_dirname)
+		goto fail;
+	memcpy(parse_dirname, dirname, strlen(dirname));
+
+	/* allocate memory for each directory level */
+	ptr = zalloc((depth) * sizeof(char *));
+	if (!ptr)
+		goto fail;
+	if (parse_path(ptr, parse_dirname))
+		goto fail;
+	parent_inode = zalloc(sizeof(struct ext2_inode));
+	if (!parent_inode)
+		goto fail;
+	first_inode = zalloc(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 (ext4fs_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) {
+		ext4fs_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:
+	free(depth_dirname);
+	free(parse_dirname);
+	free(ptr);
+	free(parent_inode);
+	free(first_inode);
+
+	return result_inode_no;
+}
+
+static int check_filename(char *filename, unsigned int blknr)
+{
+	unsigned int first_block_no_of_root;
+	int totalbytes = 0;
+	int templength = 0;
+	int status, inodeno;
+	int found = 0;
+	char *root_first_block_buffer = NULL;
+	char *root_first_block_addr = NULL;
+	struct ext2_dirent *dir = NULL;
+	struct ext2_dirent *previous_dir = NULL;
+	char *ptr = NULL;
+	struct ext_filesystem *fs = get_fs();
+
+	/* get the first block of root */
+	first_block_no_of_root = blknr;
+	root_first_block_buffer = zalloc(fs->blksz);
+	if (!root_first_block_buffer)
+		return -ENOMEM;
+	root_first_block_addr = root_first_block_buffer;
+	status = ext4fs_devread(first_block_no_of_root *
+				fs->sect_perblk, 0,
+				fs->blksz, root_first_block_buffer);
+	if (status == 0)
+		goto fail;
+
+	if (ext4fs_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
+		 */
+		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 (ext4fs_put_metadata(root_first_block_addr,
+					first_block_no_of_root))
+			goto fail;
+		return inodeno;
+	}
+fail:
+	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;
+}
+
+long int ext4fs_get_new_blk_no(void)
+{
+	short i;
+	short status;
+	int remainder;
+	unsigned int bg_idx;
+	static int prev_bg_bitmap_index = -1;
+	unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
+	struct ext_filesystem *fs = get_fs();
+	char *journal_buffer = zalloc(fs->blksz);
+	char *zero_buffer = zalloc(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 = ext4fs_devread(gd[i].block_id *
+							fs->sect_perblk, 0,
+							fs->blksz,
+							journal_buffer);
+				if (status == 0)
+					goto fail;
+				if (ext4fs_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 / blk_per_grp;
+		} else {
+			bg_idx = fs->curr_blkno / blk_per_grp;
+			remainder = fs->curr_blkno % blk_per_grp;
+			if (!remainder)
+				bg_idx--;
+		}
+
+		/*
+		 * To skip completely filled block group bitmaps
+		 * Optimize the block allocation
+		 */
+		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 + blk_per_grp;
+			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 (ext4fs_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 = ext4fs_devread(gd[bg_idx].block_id
+						* fs->sect_perblk,
+						0, fs->blksz, journal_buffer);
+			if (status == 0)
+				goto fail;
+			if (ext4fs_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:
+	free(journal_buffer);
+	free(zero_buffer);
+
+	return fs->curr_blkno;
+fail:
+	free(journal_buffer);
+	free(zero_buffer);
+
+	return -1;
+}
+
+int ext4fs_get_new_inode_no(void)
+{
+	short i;
+	short status;
+	unsigned int ibmap_idx;
+	static int prev_inode_bitmap_index = -1;
+	unsigned int inodes_per_grp = ext4fs_root->sblock.inodes_per_group;
+	struct ext_filesystem *fs = get_fs();
+	char *journal_buffer = zalloc(fs->blksz);
+	char *zero_buffer = zalloc(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_itable_unused != gd[i].free_inodes)
+					gd[i].bg_itable_unused =
+						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 * inodes_per_grp);
+				fs->first_pass_ibmap++;
+				gd[i].free_inodes--;
+				gd[i].bg_itable_unused--;
+				fs->sb->free_inodes--;
+				status = ext4fs_devread(gd[i].inode_id *
+							fs->sect_perblk, 0,
+							fs->blksz,
+							journal_buffer);
+				if (status == 0)
+					goto fail;
+				if (ext4fs_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 / inodes_per_grp;
+		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 (ext4fs_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 = ext4fs_devread(gd[ibmap_idx].inode_id
+						* fs->sect_perblk,
+						0, fs->blksz, journal_buffer);
+			if (status == 0)
+				goto fail;
+			if (ext4fs_log_journal(journal_buffer,
+						gd[ibmap_idx].inode_id))
+				goto fail;
+			prev_inode_bitmap_index = ibmap_idx;
+		}
+		if (gd[ibmap_idx].bg_itable_unused != gd[ibmap_idx].free_inodes)
+			gd[ibmap_idx].bg_itable_unused =
+					gd[ibmap_idx].free_inodes;
+		gd[ibmap_idx].free_inodes--;
+		gd[ibmap_idx].bg_itable_unused--;
+		fs->sb->free_inodes--;
+		goto success;
+	}
+
+success:
+	free(journal_buffer);
+	free(zero_buffer);
+
+	return fs->curr_inode_no;
+fail:
+	free(journal_buffer);
+	free(zero_buffer);
+
+	return -1;
+
+}
+
+
+static void alloc_single_indirect_block(struct ext2_inode *file_inode,
+					unsigned int *total_remaining_blocks,
+					unsigned int *no_blks_reqd)
+{
+	short i;
+	short status;
+	long int actual_block_no;
+	long int si_blockno;
+	/* si :single indirect */
+	unsigned int *si_buffer = NULL;
+	unsigned int *si_start_addr = NULL;
+	struct ext_filesystem *fs = get_fs();
+
+	if (*total_remaining_blocks != 0) {
+		si_buffer = zalloc(fs->blksz);
+		if (!si_buffer) {
+			printf("No Memory\n");
+			return;
+		}
+		si_start_addr = si_buffer;
+		si_blockno = ext4fs_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 = ext4fs_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 = ext4fs_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:
+	free(si_start_addr);
+}
+
+static void alloc_double_indirect_block(struct ext2_inode *file_inode,
+					unsigned int *total_remaining_blocks,
+					unsigned int *no_blks_reqd)
+{
+	short i;
+	short j;
+	short status;
+	long int actual_block_no;
+	/* di:double indirect */
+	long int di_blockno_parent;
+	long int 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 = ext4fs_get_new_blk_no();
+		if (di_blockno_parent == -1) {
+			printf("no block left to assign\n");
+			goto fail;
+		}
+		di_parent_buffer = zalloc(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 = ext4fs_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 = ext4fs_get_new_blk_no();
+			if (di_blockno_child == -1) {
+				printf("no block left to assign\n");
+				goto fail;
+			}
+			di_child_buff = zalloc(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 = ext4fs_devread(di_blockno_child *
+						fs->sect_perblk, 0,
+						fs->blksz,
+						(char *)di_child_buff);
+			memset(di_child_buff, '\0', fs->blksz);
+			/* filling of actual datablocks for each child */
+			for (j = 0; j < (fs->blksz / sizeof(int)); j++) {
+				actual_block_no = ext4fs_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);
+			free(di_child_buff_start);
+			di_child_buff_start = NULL;
+
+			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:
+	free(di_block_start_addr);
+}
+
+static void alloc_triple_indirect_block(struct ext2_inode *file_inode,
+					unsigned int *total_remaining_blocks,
+					unsigned int *no_blks_reqd)
+{
+	short i;
+	short j;
+	short k;
+	long int actual_block_no;
+	/* ti: Triple Indirect */
+	long int ti_gp_blockno;
+	long int ti_parent_blockno;
+	long int 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 = ext4fs_get_new_blk_no();
+		if (ti_gp_blockno == -1) {
+			printf("no block left to assign\n");
+			goto fail;
+		}
+		ti_gp_buff = zalloc(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 = ext4fs_get_new_blk_no();
+			if (ti_parent_blockno == -1) {
+				printf("no block left to assign\n");
+				goto fail;
+			}
+			ti_parent_buff = zalloc(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 = ext4fs_get_new_blk_no();
+				if (ti_child_blockno == -1) {
+					printf("no block left assign\n");
+					goto fail;
+				}
+				ti_child_buff = zalloc(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);
+
+				/* fill actual datablocks for each child */
+				for (k = 0; k < (fs->blksz / sizeof(int));
+					k++) {
+					actual_block_no =
+					    ext4fs_get_new_blk_no();
+					if (actual_block_no == -1) {
+						printf("no block left\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);
+				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);
+			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.triple_indir_block = ti_gp_blockno;
+	}
+fail:
+	free(ti_gp_buff_start_addr);
+}
+
+void ext4fs_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;
+
+	/* allocation of direct blocks */
+	for (i = 0; i < INDIRECT_BLOCKS; i++) {
+		direct_blockno = ext4fs_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;
+	}
+
+	alloc_single_indirect_block(file_inode, &total_remaining_blocks,
+				    &no_blks_reqd);
+	alloc_double_indirect_block(file_inode, &total_remaining_blocks,
+				    &no_blks_reqd);
+	alloc_triple_indirect_block(file_inode, &total_remaining_blocks,
+				    &no_blks_reqd);
+	*total_no_of_block += no_blks_reqd;
+}
+
+#endif
+
 static struct ext4_extent_header *ext4fs_get_extent_block
 	(struct ext2_data *data, char *buf,
 		struct ext4_extent_header *ext_block,
diff --git a/fs/ext4/ext4_common.h b/fs/ext4/ext4_common.h
index 182049d..bcfcd44 100644
--- a/fs/ext4/ext4_common.h
+++ b/fs/ext4/ext4_common.h
@@ -14,6 +14,8 @@
  * GRUB  --  GRand Unified Bootloader
  * Copyright (C) 2003, 2004  Free Software Foundation, Inc.
  *
+ * ext4write : Based on generic ext4 protocol.
+ *
  * 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
@@ -35,6 +37,10 @@
 #include <ext4fs.h>
 #include <malloc.h>
 #include <asm/errno.h>
+#if defined(CONFIG_CMD_EXT4_WRITE)
+#include "ext4_journal.h"
+#include "crc16.h"
+#endif
 
 #define YES		1
 #define NO		0
@@ -60,4 +66,23 @@ int ext4fs_find_file(const char *path, struct ext2fs_node *rootnode,
 			struct ext2fs_node **foundnode, int expecttype);
 int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name,
 			struct ext2fs_node **fnode, int *ftype);
+
+#if defined(CONFIG_CMD_EXT4_WRITE)
+uint32_t ext4fs_div_roundup(uint32_t size, uint32_t n);
+int ext4fs_checksum_update(unsigned int i);
+int ext4fs_get_parent_inode_num(const char *dirname, char *dname, int flags);
+void ext4fs_update_parent_dentry(char *filename, int *p_ino, int file_type);
+long int ext4fs_get_new_blk_no(void);
+int ext4fs_get_new_inode_no(void);
+void ext4fs_reset_block_bmap(long int blockno, unsigned char *buffer,
+					int index);
+int ext4fs_set_block_bmap(long int blockno, unsigned char *buffer, int index);
+int ext4fs_set_inode_bmap(int inode_no, unsigned char *buffer, int index);
+void ext4fs_reset_inode_bmap(int inode_no, unsigned char *buffer, int index);
+int ext4fs_iget(int inode_no, struct ext2_inode *inode);
+void ext4fs_allocate_blocks(struct ext2_inode *file_inode,
+				unsigned int total_remaining_blocks,
+				unsigned int *total_no_of_block);
+void put_ext4(uint64_t off, void *buf, uint32_t size);
+#endif
 #endif
diff --git a/fs/ext4/ext4_journal.c b/fs/ext4/ext4_journal.c
new file mode 100644
index 0000000..8a252d6
--- /dev/null
+++ b/fs/ext4/ext4_journal.c
@@ -0,0 +1,667 @@
+/*
+ * (C) Copyright 2011 - 2012 Samsung Electronics
+ * EXT4 filesystem implementation in Uboot by
+ * Uma Shankar <uma.shankar@samsung.com>
+ * Manjunatha C Achar <a.manjunatha@samsung.com>
+ *
+ * Journal data structures and headers for Journaling feature of ext4
+ * have been referred from JBD2 (Journaling Block device 2)
+ * implementation in Linux Kernel.
+ * Written by Stephen C. Tweedie <sct@redhat.com>
+ *
+ * Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <common.h>
+#include <ext4fs.h>
+#include <malloc.h>
+#include <ext_common.h>
+#include "ext4_common.h"
+
+static struct revoke_blk_list *revk_blk_list;
+static struct revoke_blk_list *prev_node;
+static int first_node = TRUE;
+
+int gindex;
+int gd_index;
+int jrnl_blk_idx;
+struct journal_log *journal_ptr[MAX_JOURNAL_ENTRIES];
+struct dirty_blocks *dirty_block_ptr[MAX_JOURNAL_ENTRIES];
+
+int ext4fs_init_journal(void)
+{
+	int i;
+	char *temp = NULL;
+	struct ext_filesystem *fs = get_fs();
+
+	/* init globals */
+	revk_blk_list = NULL;
+	prev_node = NULL;
+	gindex = 0;
+	gd_index = 0;
+	jrnl_blk_idx = 1;
+
+	for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
+		journal_ptr[i] = zalloc(sizeof(struct journal_log));
+		if (!journal_ptr[i])
+			goto fail;
+		dirty_block_ptr[i] = zalloc(sizeof(struct dirty_blocks));
+		if (!dirty_block_ptr[i])
+			goto fail;
+		journal_ptr[i]->buf = NULL;
+		journal_ptr[i]->blknr = -1;
+
+		dirty_block_ptr[i]->buf = NULL;
+		dirty_block_ptr[i]->blknr = -1;
+	}
+
+	if (fs->blksz == 4096) {
+		temp = zalloc(fs->blksz);
+		if (!temp)
+			goto fail;
+		journal_ptr[gindex]->buf = zalloc(fs->blksz);
+		if (!journal_ptr[gindex]->buf)
+			goto fail;
+		ext4fs_devread(0, 0, fs->blksz, temp);
+		memcpy(temp + SUPERBLOCK_SIZE, fs->sb, SUPERBLOCK_SIZE);
+		memcpy(journal_ptr[gindex]->buf, temp, fs->blksz);
+		journal_ptr[gindex++]->blknr = 0;
+		free(temp);
+	} else {
+		journal_ptr[gindex]->buf = zalloc(fs->blksz);
+		if (!journal_ptr[gindex]->buf)
+			goto fail;
+		memcpy(journal_ptr[gindex]->buf, fs->sb, SUPERBLOCK_SIZE);
+		journal_ptr[gindex++]->blknr = 1;
+	}
+
+	/* Check the file system state using journal super block */
+	if (ext4fs_check_journal_state(SCAN))
+		goto fail;
+	/* Check the file system state using journal super block */
+	if (ext4fs_check_journal_state(RECOVER))
+		goto fail;
+
+	return 0;
+fail:
+	return -1;
+}
+
+void ext4fs_dump_metadata(void)
+{
+	struct ext_filesystem *fs = get_fs();
+	int i;
+	for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
+		if (dirty_block_ptr[i]->blknr == -1)
+			break;
+		put_ext4((uint64_t) ((uint64_t)dirty_block_ptr[i]->blknr *
+				(uint64_t)fs->blksz), dirty_block_ptr[i]->buf,
+								fs->blksz);
+	}
+}
+
+void ext4fs_free_journal(void)
+{
+	int i;
+	for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
+		if (dirty_block_ptr[i]->blknr == -1)
+			break;
+		if (dirty_block_ptr[i]->buf)
+			free(dirty_block_ptr[i]->buf);
+	}
+
+	for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
+		if (journal_ptr[i]->blknr == -1)
+			break;
+		if (journal_ptr[i]->buf)
+			free(journal_ptr[i]->buf);
+	}
+
+	for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
+		if (journal_ptr[i])
+			free(journal_ptr[i]);
+		if (dirty_block_ptr[i])
+			free(dirty_block_ptr[i]);
+	}
+	gindex = 0;
+	gd_index = 0;
+	jrnl_blk_idx = 1;
+}
+
+int ext4fs_log_gdt(char *gd_table)
+{
+	struct ext_filesystem *fs = get_fs();
+	short i;
+	long int var = fs->gdtable_blkno;
+	for (i = 0; i < fs->no_blk_pergdt; i++) {
+		journal_ptr[gindex]->buf = zalloc(fs->blksz);
+		if (!journal_ptr[gindex]->buf)
+			return -ENOMEM;
+		memcpy(journal_ptr[gindex]->buf, gd_table, fs->blksz);
+		gd_table += fs->blksz;
+		journal_ptr[gindex++]->blknr = var++;
+	}
+
+	return 0;
+}
+
+/*
+ * This function stores the backup copy of meta data in RAM
+ * journal_buffer -- Buffer containing meta data
+ * blknr -- Block number on disk of the meta data buffer
+ */
+int ext4fs_log_journal(char *journal_buffer, long int blknr)
+{
+	struct ext_filesystem *fs = get_fs();
+	short i;
+
+	if (!journal_buffer) {
+		printf("Invalid input arguments %s\n", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
+		if (journal_ptr[i]->blknr == -1)
+			break;
+		if (journal_ptr[i]->blknr == blknr)
+			return 0;
+	}
+
+	journal_ptr[gindex]->buf = zalloc(fs->blksz);
+	if (!journal_ptr[gindex]->buf)
+		return -ENOMEM;
+
+	memcpy(journal_ptr[gindex]->buf, journal_buffer, fs->blksz);
+	journal_ptr[gindex++]->blknr = blknr;
+
+	return 0;
+}
+
+/*
+ * This function stores the modified meta data in RAM
+ * metadata_buffer -- Buffer containing meta data
+ * blknr -- Block number on disk of the meta data buffer
+ */
+int ext4fs_put_metadata(char *metadata_buffer, long int blknr)
+{
+	struct ext_filesystem *fs = get_fs();
+	if (!metadata_buffer) {
+		printf("Invalid input arguments %s\n", __func__);
+		return -EINVAL;
+	}
+	dirty_block_ptr[gd_index]->buf = zalloc(fs->blksz);
+	if (!dirty_block_ptr[gd_index]->buf)
+		return -ENOMEM;
+	memcpy(dirty_block_ptr[gd_index]->buf, metadata_buffer, fs->blksz);
+	dirty_block_ptr[gd_index++]->blknr = blknr;
+
+	return 0;
+}
+
+void print_revoke_blks(char *revk_blk)
+{
+	int offset;
+	int max;
+	long int blocknr;
+	struct journal_revoke_header_t *header;
+
+	if (revk_blk == NULL)
+		return;
+
+	header = (struct journal_revoke_header_t *) revk_blk;
+	offset = sizeof(struct journal_revoke_header_t);
+	max = be32_to_cpu(header->r_count);
+	printf("total bytes %d\n", max);
+
+	while (offset < max) {
+		blocknr = be32_to_cpu(*((long int *)(revk_blk + offset)));
+		printf("revoke blknr is %ld\n", blocknr);
+		offset += 4;
+	}
+}
+
+static struct revoke_blk_list *_get_node(void)
+{
+	struct revoke_blk_list *tmp_node;
+	tmp_node = zalloc(sizeof(struct revoke_blk_list));
+	if (tmp_node == NULL)
+		return NULL;
+	tmp_node->content = NULL;
+	tmp_node->next = NULL;
+
+	return tmp_node;
+}
+
+void ext4fs_push_revoke_blk(char *buffer)
+{
+	struct revoke_blk_list *node = NULL;
+	struct ext_filesystem *fs = get_fs();
+	if (buffer == NULL) {
+		printf("buffer ptr is NULL\n");
+		return;
+	}
+	node = _get_node();
+	if (!node) {
+		printf("_get_node: malloc failed\n");
+		return;
+	}
+
+	node->content = zalloc(fs->blksz);
+	if (node->content == NULL)
+		return;
+	memcpy(node->content, buffer, fs->blksz);
+
+	if (first_node == TRUE) {
+		revk_blk_list = node;
+		prev_node = node;
+		 first_node = FALSE;
+	} else {
+		prev_node->next = node;
+		prev_node = node;
+	}
+}
+
+void ext4fs_free_revoke_blks(void)
+{
+	struct revoke_blk_list *tmp_node = revk_blk_list;
+	struct revoke_blk_list *next_node = NULL;
+
+	while (tmp_node != NULL) {
+		if (tmp_node->content)
+			free(tmp_node->content);
+		tmp_node = tmp_node->next;
+	}
+
+	tmp_node = revk_blk_list;
+	while (tmp_node != NULL) {
+		next_node = tmp_node->next;
+		free(tmp_node);
+		tmp_node = next_node;
+	}
+
+	revk_blk_list = NULL;
+	prev_node = NULL;
+	first_node = TRUE;
+}
+
+int check_blknr_for_revoke(long int blknr, int sequence_no)
+{
+	struct journal_revoke_header_t *header;
+	int offset;
+	int max;
+	long int blocknr;
+	char *revk_blk;
+	struct revoke_blk_list *tmp_revk_node = revk_blk_list;
+	while (tmp_revk_node != NULL) {
+		revk_blk = tmp_revk_node->content;
+
+		header = (struct journal_revoke_header_t *) revk_blk;
+		if (sequence_no < be32_to_cpu(header->r_header.h_sequence)) {
+			offset = sizeof(struct journal_revoke_header_t);
+			max = be32_to_cpu(header->r_count);
+
+			while (offset < max) {
+				blocknr = be32_to_cpu(*((long int *)
+						  (revk_blk + offset)));
+				if (blocknr == blknr)
+					goto found;
+				offset += 4;
+			}
+		}
+		tmp_revk_node = tmp_revk_node->next;
+	}
+
+	return -1;
+
+found:
+	return 0;
+}
+
+/*
+ * This function parses the journal blocks and replays the
+ * suceessful transactions. A transaction is successfull
+ * if commit block is found for a descriptor block
+ * The tags in descriptor block contain the disk block
+ * numbers of the metadata  to be replayed
+ */
+void recover_transaction(int prev_desc_logical_no)
+{
+	struct ext2_inode inode_journal;
+	struct ext_filesystem *fs = get_fs();
+	struct journal_header_t *jdb;
+	long int blknr;
+	char *p_jdb;
+	int ofs, flags;
+	int i;
+	struct ext3_journal_block_tag *tag;
+	char *temp_buff = zalloc(fs->blksz);
+	char *metadata_buff = zalloc(fs->blksz);
+	if (!temp_buff || !metadata_buff)
+		goto fail;
+	i = prev_desc_logical_no;
+	ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
+			  (struct ext2_inode *)&inode_journal);
+	blknr = read_allocated_block((struct ext2_inode *)
+				     &inode_journal, i);
+	ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz, temp_buff);
+	p_jdb = (char *)temp_buff;
+	jdb = (struct journal_header_t *) temp_buff;
+	ofs = sizeof(struct journal_header_t);
+
+	do {
+		tag = (struct ext3_journal_block_tag *)&p_jdb[ofs];
+		ofs += sizeof(struct ext3_journal_block_tag);
+
+		if (ofs > fs->blksz)
+			break;
+
+		flags = be32_to_cpu(tag->flags);
+		if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID))
+			ofs += 16;
+
+		i++;
+		debug("\t\ttag %u\n", be32_to_cpu(tag->block));
+		if (revk_blk_list != NULL) {
+			if (check_blknr_for_revoke(be32_to_cpu(tag->block),
+				be32_to_cpu(jdb->h_sequence)) == 0)
+				continue;
+		}
+		blknr = read_allocated_block(&inode_journal, i);
+		ext4fs_devread(blknr * fs->sect_perblk, 0,
+			       fs->blksz, metadata_buff);
+		put_ext4((uint64_t)(be32_to_cpu(tag->block) * fs->blksz),
+			 metadata_buff, (uint32_t) fs->blksz);
+	} while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG));
+fail:
+	free(temp_buff);
+	free(metadata_buff);
+}
+
+void print_jrnl_status(int recovery_flag)
+{
+	if (recovery_flag == RECOVER)
+		printf("Journal Recovery Completed\n");
+	else
+		printf("Journal Scan Completed\n");
+}
+
+int ext4fs_check_journal_state(int recovery_flag)
+{
+	int i;
+	int DB_FOUND = NO;
+	long int blknr;
+	int transaction_state = TRANSACTION_COMPLETE;
+	int prev_desc_logical_no = 0;
+	int curr_desc_logical_no = 0;
+	int ofs, flags, block;
+	struct ext2_inode inode_journal;
+	struct journal_superblock_t *jsb = NULL;
+	struct journal_header_t *jdb = NULL;
+	char *p_jdb = NULL;
+	struct ext3_journal_block_tag *tag = NULL;
+	char *temp_buff = NULL;
+	char *temp_buff1 = NULL;
+	struct ext_filesystem *fs = get_fs();
+
+	temp_buff = zalloc(fs->blksz);
+	if (!temp_buff)
+		return -ENOMEM;
+	temp_buff1 = zalloc(fs->blksz);
+	if (!temp_buff1) {
+		free(temp_buff);
+		return -ENOMEM;
+	}
+
+	ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
+	blknr = read_allocated_block(&inode_journal, EXT2_JOURNAL_SUPERBLOCK);
+	ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz, temp_buff);
+	jsb = (struct journal_superblock_t *) temp_buff;
+
+	if (fs->sb->feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) {
+		if (recovery_flag == RECOVER)
+			printf("Recovery required\n");
+	} else {
+		if (recovery_flag == RECOVER)
+			printf("File System is consistent\n");
+		goto end;
+	}
+
+	if (be32_to_cpu(jsb->s_start) == 0)
+		goto end;
+
+	if (!(jsb->s_feature_compat &
+				cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM)))
+		jsb->s_feature_compat |=
+				cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM);
+
+	i = be32_to_cpu(jsb->s_first);
+	while (1) {
+		block = be32_to_cpu(jsb->s_first);
+		blknr = read_allocated_block(&inode_journal, i);
+		memset(temp_buff1, '\0', fs->blksz);
+		ext4fs_devread(blknr * fs->sect_perblk,
+			       0, fs->blksz, temp_buff1);
+		jdb = (struct journal_header_t *) temp_buff1;
+
+		if (be32_to_cpu(jdb->h_blocktype) ==
+		    EXT3_JOURNAL_DESCRIPTOR_BLOCK) {
+			if (be32_to_cpu(jdb->h_sequence) !=
+			    be32_to_cpu(jsb->s_sequence)) {
+				print_jrnl_status(recovery_flag);
+				break;
+			}
+
+			curr_desc_logical_no = i;
+			if (transaction_state == TRANSACTION_COMPLETE)
+				transaction_state = TRANSACTION_RUNNING;
+			else
+				return -1;
+			p_jdb = (char *)temp_buff1;
+			ofs = sizeof(struct journal_header_t);
+			do {
+				tag = (struct ext3_journal_block_tag *)
+				    &p_jdb[ofs];
+				ofs += sizeof(struct ext3_journal_block_tag);
+				if (ofs > fs->blksz)
+					break;
+				flags = be32_to_cpu(tag->flags);
+				if (!(flags & EXT3_JOURNAL_FLAG_SAME_UUID))
+					ofs += 16;
+				i++;
+				debug("\t\ttag %u\n", be32_to_cpu(tag->block));
+			} while (!(flags & EXT3_JOURNAL_FLAG_LAST_TAG));
+			i++;
+			DB_FOUND = YES;
+		} else if (be32_to_cpu(jdb->h_blocktype) ==
+				EXT3_JOURNAL_COMMIT_BLOCK) {
+			if (be32_to_cpu(jdb->h_sequence) !=
+			     be32_to_cpu(jsb->s_sequence)) {
+				print_jrnl_status(recovery_flag);
+				break;
+			}
+
+			if (transaction_state == TRANSACTION_RUNNING ||
+					(DB_FOUND == NO)) {
+				transaction_state = TRANSACTION_COMPLETE;
+				i++;
+				jsb->s_sequence =
+					cpu_to_be32(be32_to_cpu(
+						jsb->s_sequence) + 1);
+			}
+			prev_desc_logical_no = curr_desc_logical_no;
+			if ((recovery_flag == RECOVER) && (DB_FOUND == YES))
+				recover_transaction(prev_desc_logical_no);
+
+			DB_FOUND = NO;
+		} else if (be32_to_cpu(jdb->h_blocktype) ==
+				EXT3_JOURNAL_REVOKE_BLOCK) {
+			if (be32_to_cpu(jdb->h_sequence) !=
+			    be32_to_cpu(jsb->s_sequence)) {
+				print_jrnl_status(recovery_flag);
+				break;
+			}
+			if (recovery_flag == SCAN)
+				ext4fs_push_revoke_blk((char *)jdb);
+			i++;
+		} else {
+			debug("Else Case\n");
+			if (be32_to_cpu(jdb->h_sequence) !=
+			    be32_to_cpu(jsb->s_sequence)) {
+				print_jrnl_status(recovery_flag);
+				break;
+			}
+		}
+	}
+
+end:
+	if (recovery_flag == RECOVER) {
+		jsb->s_start = cpu_to_be32(1);
+		jsb->s_sequence = cpu_to_be32(be32_to_cpu(jsb->s_sequence) + 1);
+		/* get the superblock */
+		ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE,
+			       (char *)fs->sb);
+		fs->sb->feature_incompat |= EXT3_FEATURE_INCOMPAT_RECOVER;
+
+		/* Update the super block */
+		put_ext4((uint64_t) (SUPERBLOCK_SIZE),
+			 (struct ext2_sblock *)fs->sb,
+			 (uint32_t) SUPERBLOCK_SIZE);
+		ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE,
+			       (char *)fs->sb);
+
+		blknr = read_allocated_block(&inode_journal,
+					 EXT2_JOURNAL_SUPERBLOCK);
+		put_ext4((uint64_t) (blknr * fs->blksz),
+			 (struct journal_superblock_t *)temp_buff,
+			 (uint32_t) fs->blksz);
+		ext4fs_free_revoke_blks();
+	}
+	free(temp_buff);
+	free(temp_buff1);
+
+	return 0;
+}
+
+static void update_descriptor_block(long int blknr)
+{
+	int i;
+	long int jsb_blknr;
+	struct journal_header_t jdb;
+	struct ext3_journal_block_tag tag;
+	struct ext2_inode inode_journal;
+	struct journal_superblock_t *jsb = NULL;
+	char *buf = NULL;
+	char *temp = NULL;
+	struct ext_filesystem *fs = get_fs();
+	char *temp_buff = zalloc(fs->blksz);
+	if (!temp_buff)
+		return;
+
+	ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
+	jsb_blknr = read_allocated_block(&inode_journal,
+					 EXT2_JOURNAL_SUPERBLOCK);
+	ext4fs_devread(jsb_blknr * fs->sect_perblk, 0, fs->blksz, temp_buff);
+	jsb = (struct journal_superblock_t *) temp_buff;
+
+	jdb.h_blocktype = cpu_to_be32(EXT3_JOURNAL_DESCRIPTOR_BLOCK);
+	jdb.h_magic = cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER);
+	jdb.h_sequence = jsb->s_sequence;
+	buf = zalloc(fs->blksz);
+	if (!buf) {
+		free(temp_buff);
+		return;
+	}
+	temp = buf;
+	memcpy(buf, &jdb, sizeof(struct journal_header_t));
+	temp += sizeof(struct journal_header_t);
+
+	for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
+		if (journal_ptr[i]->blknr == -1)
+			break;
+
+		tag.block = cpu_to_be32(journal_ptr[i]->blknr);
+		tag.flags = cpu_to_be32(EXT3_JOURNAL_FLAG_SAME_UUID);
+		memcpy(temp, &tag, sizeof(struct ext3_journal_block_tag));
+		temp = temp + sizeof(struct ext3_journal_block_tag);
+	}
+
+	tag.block = cpu_to_be32(journal_ptr[--i]->blknr);
+	tag.flags = cpu_to_be32(EXT3_JOURNAL_FLAG_LAST_TAG);
+	memcpy(temp - sizeof(struct ext3_journal_block_tag), &tag,
+	       sizeof(struct ext3_journal_block_tag));
+	put_ext4((uint64_t) (blknr * fs->blksz), buf, (uint32_t) fs->blksz);
+
+	free(temp_buff);
+	free(buf);
+}
+
+static void update_commit_block(long int blknr)
+{
+	struct journal_header_t jdb;
+	struct ext_filesystem *fs = get_fs();
+	char *buf = NULL;
+	struct ext2_inode inode_journal;
+	struct journal_superblock_t *jsb;
+	long int jsb_blknr;
+	char *temp_buff = zalloc(fs->blksz);
+	if (!temp_buff)
+		return;
+
+	ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
+	jsb_blknr = read_allocated_block(&inode_journal,
+					 EXT2_JOURNAL_SUPERBLOCK);
+	ext4fs_devread(jsb_blknr * fs->sect_perblk, 0, fs->blksz, temp_buff);
+	jsb = (struct journal_superblock_t *) temp_buff;
+
+	jdb.h_blocktype = cpu_to_be32(EXT3_JOURNAL_COMMIT_BLOCK);
+	jdb.h_magic = cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER);
+	jdb.h_sequence = jsb->s_sequence;
+	buf = zalloc(fs->blksz);
+	if (!buf) {
+		free(temp_buff);
+		return;
+	}
+	memcpy(buf, &jdb, sizeof(struct journal_header_t));
+	put_ext4((uint64_t) (blknr * fs->blksz), buf, (uint32_t) fs->blksz);
+
+	free(temp_buff);
+	free(buf);
+}
+
+void ext4fs_update_journal(void)
+{
+	struct ext2_inode inode_journal;
+	struct ext_filesystem *fs = get_fs();
+	long int blknr;
+	int i;
+	ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, &inode_journal);
+	blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++);
+	update_descriptor_block(blknr);
+	for (i = 0; i < MAX_JOURNAL_ENTRIES; i++) {
+		if (journal_ptr[i]->blknr == -1)
+			break;
+		blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++);
+		put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz),
+			 journal_ptr[i]->buf, fs->blksz);
+	}
+	blknr = read_allocated_block(&inode_journal, jrnl_blk_idx++);
+	update_commit_block(blknr);
+	printf("update journal finished\n");
+}
diff --git a/fs/ext4/ext4_journal.h b/fs/ext4/ext4_journal.h
new file mode 100644
index 0000000..224f130
--- /dev/null
+++ b/fs/ext4/ext4_journal.h
@@ -0,0 +1,141 @@
+/*
+ * (C) Copyright 2011 - 2012 Samsung Electronics
+ * EXT4 filesystem implementation in Uboot by
+ * Uma Shankar <uma.shankar@samsung.com>
+ * Manjunatha C Achar <a.manjunatha@samsung.com>
+ *
+ * Journal data structures and headers for Journaling feature of ext4
+ * have been referred from JBD2 (Journaling Block device 2)
+ * implementation in Linux Kernel.
+ *
+ * Written by Stephen C. Tweedie <sct@redhat.com>
+ *
+ * Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __EXT4_JRNL__
+#define __EXT4_JRNL__
+
+#define EXT2_JOURNAL_INO		8	/* Journal inode */
+#define EXT2_JOURNAL_SUPERBLOCK	0	/* Journal  Superblock number */
+
+#define JBD2_FEATURE_COMPAT_CHECKSUM	0x00000001
+#define EXT3_JOURNAL_MAGIC_NUMBER	0xc03b3998U
+#define TRANSACTION_RUNNING		1
+#define TRANSACTION_COMPLETE		0
+#define EXT3_FEATURE_INCOMPAT_RECOVER	0x0004	/* Needs recovery */
+#define EXT3_JOURNAL_DESCRIPTOR_BLOCK	1
+#define EXT3_JOURNAL_COMMIT_BLOCK	2
+#define EXT3_JOURNAL_SUPERBLOCK_V1	3
+#define EXT3_JOURNAL_SUPERBLOCK_V2	4
+#define EXT3_JOURNAL_REVOKE_BLOCK	5
+#define EXT3_JOURNAL_FLAG_ESCAPE	1
+#define EXT3_JOURNAL_FLAG_SAME_UUID	2
+#define EXT3_JOURNAL_FLAG_DELETED	4
+#define EXT3_JOURNAL_FLAG_LAST_TAG	8
+
+/* Maximum entries in 1 journal transaction */
+#define MAX_JOURNAL_ENTRIES 100
+struct journal_log {
+	char *buf;
+	int blknr;
+};
+
+struct dirty_blocks {
+	char *buf;
+	int blknr;
+};
+
+/* Standard header for all descriptor blocks: */
+struct journal_header_t {
+	__u32 h_magic;
+	__u32 h_blocktype;
+	__u32 h_sequence;
+};
+
+/* The journal superblock.  All fields are in big-endian byte order. */
+struct journal_superblock_t {
+	/* 0x0000 */
+	struct journal_header_t s_header;
+
+	/* Static information describing the journal */
+	__u32 s_blocksize;	/* journal device blocksize */
+	__u32 s_maxlen;		/* total blocks in journal file */
+	__u32 s_first;		/* first block of log information */
+
+	/* Dynamic information describing the current state of the log */
+	__u32 s_sequence;	/* first commit ID expected in log */
+	__u32 s_start;		/* blocknr of start of log */
+
+	/* Error value, as set by journal_abort(). */
+	__s32 s_errno;
+
+	/* Remaining fields are only valid in a version-2 superblock */
+	__u32 s_feature_compat;	/* compatible feature set */
+	__u32 s_feature_incompat;	/* incompatible feature set */
+	__u32 s_feature_ro_compat;	/* readonly-compatible feature set */
+	/* 0x0030 */
+	__u8 s_uuid[16];	/* 128-bit uuid for journal */
+
+	/* 0x0040 */
+	__u32 s_nr_users;	/* Nr of filesystems sharing log */
+
+	__u32 s_dynsuper;	/* Blocknr of dynamic superblock copy */
+
+	/* 0x0048 */
+	__u32 s_max_transaction;	/* Limit of journal blocks per trans. */
+	__u32 s_max_trans_data;	/* Limit of data blocks per trans. */
+
+	/* 0x0050 */
+	__u32 s_padding[44];
+
+	/* 0x0100 */
+	__u8 s_users[16 * 48];	/* ids of all fs'es sharing the log */
+	/* 0x0400 */
+} ;
+
+struct ext3_journal_block_tag {
+	uint32_t block;
+	uint32_t flags;
+};
+
+struct journal_revoke_header_t {
+	struct journal_header_t r_header;
+	int r_count;		/* Count of bytes used in the block */
+};
+
+struct revoke_blk_list {
+	char *content;		/* revoke block itself */
+	struct revoke_blk_list *next;
+};
+
+extern struct ext2_data *ext4fs_root;
+
+int ext4fs_init_journal(void);
+int ext4fs_log_gdt(char *gd_table);
+int ext4fs_check_journal_state(int recovery_flag);
+int ext4fs_log_journal(char *journal_buffer, long int blknr);
+int ext4fs_put_metadata(char *metadata_buffer, long int blknr);
+void ext4fs_update_journal(void);
+void ext4fs_dump_metadata(void);
+void ext4fs_push_revoke_blk(char *buffer);
+void ext4fs_free_journal(void);
+void ext4fs_free_revoke_blks(void);
+#endif
diff --git a/fs/ext4/ext4fs.c b/fs/ext4/ext4fs.c
index 1287bf0..114c2a2 100644
--- a/fs/ext4/ext4fs.c
+++ b/fs/ext4/ext4fs.c
@@ -16,6 +16,8 @@
  * GRUB  --  GRand Unified Bootloader
  * Copyright (C) 2003, 2004  Free Software Foundation, Inc.
  *
+ * ext4write : Based on generic ext4 protocol.
+ *
  * 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
@@ -226,3 +228,962 @@ int ext4fs_read(char *buf, unsigned len)
 
 	return ext4fs_read_file(ext4fs_file, 0, len, buf);
 }
+
+#if defined(CONFIG_CMD_EXT4_WRITE)
+static void ext4fs_update(void)
+{
+	short i;
+	ext4fs_update_journal();
+	struct ext_filesystem *fs = get_fs();
+
+	/* update  super block */
+	put_ext4((uint64_t)(SUPERBLOCK_SIZE),
+		 (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE);
+
+	/* update block groups */
+	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], fs->blksz);
+	}
+
+	/* update inode table groups */
+	for (i = 0; i < fs->no_blkgrp; i++) {
+		put_ext4((uint64_t) (fs->gd[i].inode_id * fs->blksz),
+			 fs->inode_bmaps[i], fs->blksz);
+	}
+
+	/* update the block group descriptor table */
+	put_ext4((uint64_t)(fs->gdtable_blkno * fs->blksz),
+		 (struct ext2_block_group *)fs->gdtable,
+		 (fs->blksz * fs->no_blk_pergdt));
+
+	ext4fs_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 memory for gdtable */
+	fs->gdtable = zalloc(fs->blksz * fs->no_blk_pergdt);
+	if (!fs->gdtable)
+		return -ENOMEM;
+	/* read the group descriptor table */
+	status = ext4fs_devread(fs->gdtable_blkno * fs->sect_perblk, 0,
+				fs->blksz * fs->no_blk_pergdt, fs->gdtable);
+	if (status == 0)
+		goto fail;
+
+	if (ext4fs_log_gdt(fs->gdtable)) {
+		printf("Error in ext4fs_log_gdt\n");
+		return -1;
+	}
+
+	return 0;
+fail:
+	free(fs->gdtable);
+	fs->gdtable = NULL;
+
+	return -1;
+}
+
+static void delete_single_indirect_block(struct ext2_inode *inode)
+{
+	struct ext2_block_group *gd = NULL;
+	static int prev_bg_bmap_idx = -1;
+	long int blknr;
+	int remainder;
+	int bg_idx;
+	int status;
+	unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
+	struct ext_filesystem *fs = get_fs();
+	char *journal_buffer = zalloc(fs->blksz);
+	if (!journal_buffer) {
+		printf("No memory\n");
+		return;
+	}
+	/* get  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 / blk_per_grp;
+		} else {
+			bg_idx = blknr / blk_per_grp;
+			remainder = blknr % blk_per_grp;
+			if (!remainder)
+				bg_idx--;
+		}
+		ext4fs_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_bmap_idx != bg_idx) {
+			status =
+			    ext4fs_devread(gd[bg_idx].block_id *
+					   fs->sect_perblk, 0, fs->blksz,
+					   journal_buffer);
+			if (status == 0)
+				goto fail;
+			if (ext4fs_log_journal
+			    (journal_buffer, gd[bg_idx].block_id))
+				goto fail;
+			prev_bg_bmap_idx = bg_idx;
+		}
+	}
+fail:
+	free(journal_buffer);
+}
+
+static void delete_double_indirect_block(struct ext2_inode *inode)
+{
+	int i;
+	short status;
+	static int prev_bg_bmap_idx = -1;
+	long int blknr;
+	int remainder;
+	int bg_idx;
+	unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
+	unsigned int *di_buffer = NULL;
+	unsigned int *DIB_start_addr = NULL;
+	struct ext2_block_group *gd = NULL;
+	struct ext_filesystem *fs = get_fs();
+	char *journal_buffer = zalloc(fs->blksz);
+	if (!journal_buffer) {
+		printf("No memory\n");
+		return;
+	}
+	/* get the block group descriptor table */
+	gd = (struct ext2_block_group *)fs->gdtable;
+
+	if (inode->b.blocks.double_indir_block != 0) {
+		di_buffer = zalloc(fs->blksz);
+		if (!di_buffer) {
+			printf("No memory\n");
+			return;
+		}
+		DIB_start_addr = (unsigned int *)di_buffer;
+		blknr = inode->b.blocks.double_indir_block;
+		status = ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz,
+					(char *)di_buffer);
+		for (i = 0; i < fs->blksz / sizeof(int); i++) {
+			if (*di_buffer == 0)
+				break;
+
+			debug("DICB releasing %u\n", *di_buffer);
+			if (fs->blksz != 1024) {
+				bg_idx = (*di_buffer) / blk_per_grp;
+			} else {
+				bg_idx = (*di_buffer) / blk_per_grp;
+				remainder = (*di_buffer) % blk_per_grp;
+				if (!remainder)
+					bg_idx--;
+			}
+			ext4fs_reset_block_bmap(*di_buffer,
+					fs->blk_bmaps[bg_idx], bg_idx);
+			di_buffer++;
+			gd[bg_idx].free_blocks++;
+			fs->sb->free_blocks++;
+			/* journal backup */
+			if (prev_bg_bmap_idx != bg_idx) {
+				status = ext4fs_devread(gd[bg_idx].block_id
+							* fs->sect_perblk, 0,
+							fs->blksz,
+							journal_buffer);
+				if (status == 0)
+					goto fail;
+
+				if (ext4fs_log_journal(journal_buffer,
+							gd[bg_idx].block_id))
+					goto fail;
+				prev_bg_bmap_idx = bg_idx;
+			}
+		}
+
+		/* removing the parent double indirect block */
+		blknr = inode->b.blocks.double_indir_block;
+		if (fs->blksz != 1024) {
+			bg_idx = blknr / blk_per_grp;
+		} else {
+			bg_idx = blknr / blk_per_grp;
+			remainder = blknr % blk_per_grp;
+			if (!remainder)
+				bg_idx--;
+		}
+		ext4fs_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_bmap_idx != bg_idx) {
+			memset(journal_buffer, '\0', fs->blksz);
+			status = ext4fs_devread(gd[bg_idx].block_id *
+						fs->sect_perblk, 0, fs->blksz,
+						journal_buffer);
+			if (status == 0)
+				goto fail;
+
+			if (ext4fs_log_journal(journal_buffer,
+						gd[bg_idx].block_id))
+				goto fail;
+			prev_bg_bmap_idx = bg_idx;
+		}
+		debug("DIPB releasing %ld\n", blknr);
+	}
+fail:
+	free(DIB_start_addr);
+	free(journal_buffer);
+}
+
+static void delete_triple_indirect_block(struct ext2_inode *inode)
+{
+	int i, j;
+	short status;
+	static int prev_bg_bmap_idx = -1;
+	long int blknr;
+	int remainder;
+	int bg_idx;
+	unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
+	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 = NULL;
+	struct ext_filesystem *fs = get_fs();
+	char *journal_buffer = zalloc(fs->blksz);
+	if (!journal_buffer) {
+		printf("No memory\n");
+		return;
+	}
+	/* get block group descriptor table */
+	gd = (struct ext2_block_group *)fs->gdtable;
+
+	if (inode->b.blocks.triple_indir_block != 0) {
+		tigp_buffer = zalloc(fs->blksz);
+		if (!tigp_buffer) {
+			printf("No memory\n");
+			return;
+		}
+		tib_start_addr = (unsigned int *)tigp_buffer;
+		blknr = inode->b.blocks.triple_indir_block;
+		status = ext4fs_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("tigp buffer releasing %u\n", *tigp_buffer);
+
+			tip_buffer = zalloc(fs->blksz);
+			if (!tip_buffer)
+				goto fail;
+			tipb_start_addr = (unsigned int *)tip_buffer;
+			status = ext4fs_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) / blk_per_grp;
+				} else {
+					bg_idx = (*tip_buffer) / blk_per_grp;
+
+					remainder = (*tip_buffer) % blk_per_grp;
+					if (!remainder)
+						bg_idx--;
+				}
+
+				ext4fs_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_bmap_idx != bg_idx) {
+					status =
+					    ext4fs_devread(gd[bg_idx].block_id *
+							   fs->sect_perblk, 0,
+							   fs->blksz,
+							   journal_buffer);
+					if (status == 0)
+						goto fail;
+
+					if (ext4fs_log_journal(journal_buffer,
+							       gd[bg_idx].
+							       block_id))
+						goto fail;
+					prev_bg_bmap_idx = bg_idx;
+				}
+			}
+			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) / blk_per_grp;
+			} else {
+				bg_idx = (*tigp_buffer) / blk_per_grp;
+
+				remainder = (*tigp_buffer) % blk_per_grp;
+				if (!remainder)
+					bg_idx--;
+			}
+			ext4fs_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_bmap_idx != bg_idx) {
+				memset(journal_buffer, '\0', fs->blksz);
+				status =
+				    ext4fs_devread(gd[bg_idx].block_id *
+						   fs->sect_perblk, 0,
+						   fs->blksz, journal_buffer);
+				if (status == 0)
+					goto fail;
+
+				if (ext4fs_log_journal(journal_buffer,
+							gd[bg_idx].block_id))
+					goto fail;
+				prev_bg_bmap_idx = bg_idx;
+			}
+		}
+
+		/* removing the grand parent triple indirect block */
+		blknr = inode->b.blocks.triple_indir_block;
+		if (fs->blksz != 1024) {
+			bg_idx = blknr / blk_per_grp;
+		} else {
+			bg_idx = blknr / blk_per_grp;
+			remainder = blknr % blk_per_grp;
+			if (!remainder)
+				bg_idx--;
+		}
+		ext4fs_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_bmap_idx != bg_idx) {
+			memset(journal_buffer, '\0', fs->blksz);
+			status = ext4fs_devread(gd[bg_idx].block_id *
+						fs->sect_perblk, 0, fs->blksz,
+						journal_buffer);
+			if (status == 0)
+				goto fail;
+
+			if (ext4fs_log_journal(journal_buffer,
+						gd[bg_idx].block_id))
+				goto fail;
+			prev_bg_bmap_idx = bg_idx;
+		}
+		debug("tigp buffer itself releasing %ld\n", blknr);
+	}
+fail:
+	free(tib_start_addr);
+	free(tipb_start_addr);
+	free(journal_buffer);
+}
+
+static int ext4fs_delete_file(int inodeno)
+{
+	struct ext2_inode inode;
+	short status;
+	int i;
+	int remainder;
+	long int blknr;
+	int bg_idx;
+	int ibmap_idx;
+	char *read_buffer = NULL;
+	char *start_block_address = NULL;
+	unsigned int no_blocks;
+
+	static int prev_bg_bmap_idx = -1;
+	unsigned int inodes_per_block;
+	long int blkno;
+	unsigned int blkoff;
+	unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group;
+	unsigned int inode_per_grp = ext4fs_root->sblock.inodes_per_group;
+	struct ext2_inode *inode_buffer = NULL;
+	struct ext2_block_group *gd = NULL;
+	struct ext_filesystem *fs = get_fs();
+	char *journal_buffer = zalloc(fs->blksz);
+	if (!journal_buffer)
+		return -ENOMEM;
+	/* 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_FL) {
+		struct ext2fs_node *node_inode =
+		    zalloc(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 / blk_per_grp;
+			} else {
+				bg_idx = blknr / blk_per_grp;
+				remainder = blknr % blk_per_grp;
+				if (!remainder)
+					bg_idx--;
+			}
+			ext4fs_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_bmap_idx != bg_idx) {
+				status =
+				    ext4fs_devread(gd[bg_idx].block_id *
+						   fs->sect_perblk, 0,
+						   fs->blksz, journal_buffer);
+				if (status == 0)
+					goto fail;
+				if (ext4fs_log_journal(journal_buffer,
+							gd[bg_idx].block_id))
+					goto fail;
+				prev_bg_bmap_idx = bg_idx;
+			}
+		}
+		if (node_inode) {
+			free(node_inode);
+			node_inode = NULL;
+		}
+	} else {
+
+		delete_single_indirect_block(&inode);
+		delete_double_indirect_block(&inode);
+		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 / blk_per_grp;
+			} else {
+				bg_idx = blknr / blk_per_grp;
+				remainder = blknr % blk_per_grp;
+				if (!remainder)
+					bg_idx--;
+			}
+			ext4fs_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_bmap_idx != bg_idx) {
+				memset(journal_buffer, '\0', fs->blksz);
+				status = ext4fs_devread(gd[bg_idx].block_id
+							* fs->sect_perblk,
+							0, fs->blksz,
+							journal_buffer);
+				if (status == 0)
+					goto fail;
+				if (ext4fs_log_journal(journal_buffer,
+						gd[bg_idx].block_id))
+					goto fail;
+				prev_bg_bmap_idx = bg_idx;
+			}
+		}
+	}
+
+	/* from the inode no to blockno */
+	inodes_per_block = fs->blksz / fs->inodesz;
+	ibmap_idx = inodeno / inode_per_grp;
+
+	/* get the block no */
+	inodeno--;
+	blkno = __le32_to_cpu(gd[ibmap_idx].inode_table_id) +
+		(inodeno % __le32_to_cpu(inode_per_grp)) / 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 = zalloc(fs->blksz);
+	if (!read_buffer)
+		goto fail;
+	start_block_address = read_buffer;
+	status = ext4fs_devread(blkno * fs->sect_perblk,
+				0, fs->blksz, read_buffer);
+	if (status == 0)
+		goto fail;
+
+	if (ext4fs_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 (ext4fs_put_metadata(start_block_address, blkno))
+		goto fail;
+
+	/* update the respective inode bitmaps */
+	inodeno++;
+	ext4fs_reset_inode_bmap(inodeno, fs->inode_bmaps[ibmap_idx], ibmap_idx);
+	gd[ibmap_idx].free_inodes++;
+	fs->sb->free_inodes++;
+	/* journal backup */
+	memset(journal_buffer, '\0', fs->blksz);
+	status = ext4fs_devread(gd[ibmap_idx].inode_id *
+				fs->sect_perblk, 0, fs->blksz, journal_buffer);
+	if (status == 0)
+		goto fail;
+	if (ext4fs_log_journal(journal_buffer, gd[ibmap_idx].inode_id))
+		goto fail;
+
+	ext4fs_update();
+	ext4fs_deinit();
+
+	if (ext4fs_init() != 0) {
+		printf("error in File System init\n");
+		goto fail;
+	}
+
+	free(start_block_address);
+	free(journal_buffer);
+
+	return 0;
+fail:
+	free(start_block_address);
+	free(journal_buffer);
+
+	return -1;
+}
+
+int ext4fs_init(void)
+{
+	short status;
+	int i;
+	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;
+
+	/* get the superblock */
+	fs->sb = zalloc(SUPERBLOCK_SIZE);
+	if (!fs->sb)
+		return -ENOMEM;
+	if (!ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE,
+			(char *)fs->sb))
+		goto fail;
+
+	/* init journal */
+	if (ext4fs_init_journal())
+		goto fail;
+
+	/* get total no of blockgroups */
+	fs->no_blkgrp = (uint32_t)ext4fs_div_roundup(
+			(ext4fs_root->sblock.total_blocks -
+			ext4fs_root->sblock.first_data_block),
+			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("Error in getting the block group descriptor table\n");
+		goto fail;
+	}
+	fs->gd = (struct ext2_block_group *)fs->gdtable;
+
+	/* load all the available bitmap block of the partition */
+	fs->blk_bmaps = zalloc(fs->no_blkgrp * sizeof(char *));
+	if (!fs->blk_bmaps)
+		goto fail;
+	for (i = 0; i < fs->no_blkgrp; i++) {
+		fs->blk_bmaps[i] = zalloc(fs->blksz);
+		if (!fs->blk_bmaps[i])
+			goto fail;
+	}
+
+	for (i = 0; i < fs->no_blkgrp; i++) {
+		status =
+		    ext4fs_devread(fs->gd[i].block_id * fs->sect_perblk, 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 = zalloc(fs->no_blkgrp * sizeof(unsigned char *));
+	if (!fs->inode_bmaps)
+		goto fail;
+	for (i = 0; i < fs->no_blkgrp; i++) {
+		fs->inode_bmaps[i] = zalloc(fs->blksz);
+		if (!fs->inode_bmaps[i])
+			goto fail;
+	}
+
+	for (i = 0; i < fs->no_blkgrp; i++) {
+		status = ext4fs_devread(fs->gd[i].inode_id * fs->sect_perblk,
+					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 = zalloc(fs->blksz);
+	if (temp_buff) {
+		ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
+				  &inode_journal);
+		blknr = read_allocated_block(&inode_journal,
+					EXT2_JOURNAL_SUPERBLOCK);
+		ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz,
+			       temp_buff);
+		jsb = (struct journal_superblock_t *)temp_buff;
+		jsb->s_start = cpu_to_be32(0);
+		put_ext4((uint64_t) (blknr * fs->blksz),
+			 (struct journal_superblock_t *)temp_buff, fs->blksz);
+		free(temp_buff);
+	}
+	ext4fs_free_journal();
+
+	/* get the superblock */
+	ext4fs_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);
+	free(fs->sb);
+	fs->sb = NULL;
+
+	if (fs->blk_bmaps) {
+		for (i = 0; i < fs->no_blkgrp; 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++) {
+			free(fs->inode_bmaps[i]);
+			fs->inode_bmaps[i] = NULL;
+		}
+		free(fs->inode_bmaps);
+		fs->inode_bmaps = NULL;
+	}
+
+
+	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;
+}
+
+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(const char *fname, unsigned char *buffer,
+					unsigned long sizebytes)
+{
+	int ret = 0;
+	struct ext2_inode *file_inode = NULL;
+	unsigned char *inode_buffer = NULL;
+	int parent_inodeno;
+	int inodeno;
+	time_t timestamp = 0;
+
+	uint64_t bytes_reqd_for_file;
+	unsigned int blks_reqd_for_file;
+	unsigned int blocks_remaining;
+	int existing_file_inodeno;
+	char filename[256];
+
+	char *temp_ptr = NULL;
+	long int itable_blkno;
+	long int parent_itable_blkno;
+	long int blkoff;
+	struct ext2_sblock *sblock = &(ext4fs_root->sblock);
+	unsigned int inodes_per_block;
+	unsigned int ibmap_idx;
+	struct ext_filesystem *fs = get_fs();
+	g_parent_inode = zalloc(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 = ext4fs_get_parent_inode_num(fname, filename, F_FILE);
+	if (parent_inodeno == -1)
+		goto fail;
+	if (ext4fs_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 */
+	bytes_reqd_for_file = sizebytes;
+	blks_reqd_for_file = bytes_reqd_for_file / fs->blksz;
+	if (bytes_reqd_for_file % fs->blksz != 0) {
+		blks_reqd_for_file++;
+		debug("total bytes for a file %u\n", blks_reqd_for_file);
+	}
+	blocks_remaining = blks_reqd_for_file;
+	/* test for available space in partition */
+	if (fs->sb->free_blocks < blks_reqd_for_file) {
+		printf("Not enough space on partition !!!\n");
+		goto fail;
+	}
+
+	ext4fs_update_parent_dentry(filename, &inodeno, FILETYPE_REG);
+	/* prepare file inode */
+	inode_buffer = zalloc(fs->inodesz);
+	if (!inode_buffer)
+		goto fail;
+	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 */
+	ext4fs_allocate_blocks(file_inode, blocks_remaining,
+			       &blks_reqd_for_file);
+	file_inode->blockcnt = (blks_reqd_for_file * fs->blksz) / SECTOR_SIZE;
+
+	temp_ptr = zalloc(fs->blksz);
+	if (!temp_ptr)
+		goto fail;
+	ibmap_idx = inodeno / ext4fs_root->sblock.inodes_per_group;
+	inodeno--;
+	itable_blkno = __le32_to_cpu(fs->gd[ibmap_idx].inode_table_id) +
+			(inodeno % __le32_to_cpu(sblock->inodes_per_group)) /
+			inodes_per_block;
+	blkoff = (inodeno % inodes_per_block) * fs->inodesz;
+	ext4fs_devread(itable_blkno * fs->sect_perblk, 0, fs->blksz, temp_ptr);
+	if (ext4fs_log_journal(temp_ptr, itable_blkno))
+		goto fail;
+
+	memcpy(temp_ptr + blkoff, inode_buffer, fs->inodesz);
+	if (ext4fs_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;
+	}
+	ibmap_idx = parent_inodeno / ext4fs_root->sblock.inodes_per_group;
+	parent_inodeno--;
+	parent_itable_blkno = __le32_to_cpu(fs->gd[ibmap_idx].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);
+		ext4fs_devread(parent_itable_blkno * fs->sect_perblk,
+			       0, fs->blksz, temp_ptr);
+		if (ext4fs_log_journal(temp_ptr, parent_itable_blkno))
+			goto fail;
+
+		memcpy(temp_ptr + blkoff, g_parent_inode,
+			sizeof(struct ext2_inode));
+		if (ext4fs_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 (ext4fs_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;
+	free(inode_buffer);
+	free(g_parent_inode);
+	g_parent_inode = NULL;
+
+	return 0;
+fail:
+	ext4fs_deinit();
+	free(inode_buffer);
+	free(g_parent_inode);
+	g_parent_inode = NULL;
+
+	return -1;
+}
+#endif
diff --git a/include/ext4fs.h b/include/ext4fs.h
index 55f9ccc..a56e302 100644
--- a/include/ext4fs.h
+++ b/include/ext4fs.h
@@ -117,6 +117,18 @@ extern block_dev_desc_t *ext4_dev_desc;
 extern struct ext2_data *ext4fs_root;
 extern struct ext2fs_node *ext4fs_file;
 
+#if defined(CONFIG_CMD_EXT4_WRITE)
+extern struct ext2_inode *g_parent_inode;
+extern int gd_index;
+extern int gindex;
+
+int ext4fs_init(void);
+void ext4fs_deinit(void);
+int ext4fs_filename_check(char *filename);
+int ext4fs_write(const char *fname, unsigned char *buffer,
+				unsigned long sizebytes);
+#endif
+
 struct ext_filesystem *get_fs(void);
 int init_fs(block_dev_desc_t *dev_desc);
 void deinit_fs(block_dev_desc_t *dev_desc);
diff --git a/include/ext_common.h b/include/ext_common.h
index ef71e1d..b671fc3 100644
--- a/include/ext_common.h
+++ b/include/ext_common.h
@@ -191,6 +191,8 @@ int do_ext2load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
 int do_ext4_load(cmd_tbl_t *cmdtp, int flag, int argc,
 					char *const argv[]);
 int do_ext4_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]);
+int do_ext4_write(cmd_tbl_t *cmdtp, int flag, int argc,
+				char *const argv[]);
 int do_ext_load(cmd_tbl_t *cmdtp, int flag, int argc,
 					char *const argv[]);
 int do_ext_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]);
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [U-Boot] [PATCH V5 2/2] ext4fs write support
  2012-05-25 15:52     ` [U-Boot] [PATCH V5 " Uma Shankar
@ 2012-08-09 21:50       ` Wolfgang Denk
  2012-08-13 11:55         ` Wolfgang Denk
  0 siblings, 1 reply; 14+ messages in thread
From: Wolfgang Denk @ 2012-08-09 21:50 UTC (permalink / raw)
  To: u-boot

Dear Uma Shankar,

In message <1337961169-21233-1-git-send-email-uma.shankar@samsung.com> you wrote:
> 
> Signed-off-by: Uma Shankar <uma.shankar@samsung.com>
> Signed-off-by: Manjunatha C Achar <a.manjunatha@samsung.com>
> Signed-off-by: Iqbal Shareef <iqbal.ams@samsung.com>
> Signed-off-by: Hakgoo Lee <goodguy.lee@samsung.com>
> ---
> Changes for v4:
>         - Redesigned ext2, ext4 command interface
>         - Removed ext2 folder from fs/
>         - Memory Leak issue handled
> 
> Changes for v3:
>         - Copyright has been updated in respective files
>         - ext4fs has been made independant of ext2fs.c
>         - Fixed API namespace
>         - Removed endianness conversion API, used uboot defined API
>           for the same
>         - Fixed coding style issues
>         - Moved README.ext4 file into doc folder
> 
> Changes for v2:
>         - Code cleanup, changed comment style
>         - camel case removed, resolved code alignment issues
>         - memory allocation logic changed, removed busybox logic
>         - Modified ext4 load to remove grub dependency (GPLv3)
>         - Introduced new Config for ext4 write
> 
> Changes for v1:
>         - Removed checkpatch warnings and errors
>         - Moved common API's of ext2 and ext4 to one generic header file
> 
> 
> ---
>  common/cmd_ext4.c      |  141 +++++
>  doc/README.ext4        |   46 ++
>  fs/ext4/Makefile       |    1 +
>  fs/ext4/crc16.c        |   62 +++
>  fs/ext4/crc16.h        |   16 +
>  fs/ext4/ext4_common.c  | 1353 ++++++++++++++++++++++++++++++++++++++++++++++++
>  fs/ext4/ext4_common.h  |   25 +
>  fs/ext4/ext4_journal.c |  667 ++++++++++++++++++++++++
>  fs/ext4/ext4_journal.h |  141 +++++
>  fs/ext4/ext4fs.c       |  961 ++++++++++++++++++++++++++++++++++
>  include/ext4fs.h       |   12 +
>  include/ext_common.h   |    2 +
>  12 files changed, 3427 insertions(+), 0 deletions(-)
>  create mode 100644 doc/README.ext4
>  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

Applied to "ext4" branch, thanks.

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 at denx.de
The human race has one really effective weapon, and that is laughter.
                                                         - Mark Twain

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [U-Boot] [PATCH V5 2/2] ext4fs write support
  2012-08-09 21:50       ` Wolfgang Denk
@ 2012-08-13 11:55         ` Wolfgang Denk
  2012-08-13 13:52           ` uma.shankar at samsung.com
  0 siblings, 1 reply; 14+ messages in thread
From: Wolfgang Denk @ 2012-08-13 11:55 UTC (permalink / raw)
  To: u-boot

Dear Uma Shankar,

In message <20120809215050.89DE220401A@gemini.denx.de> I wrote:
> 
> Applied to "ext4" branch, thanks.

I did some performance tests on a MPC5200 based board using the IDE
interface (no DMA):

=> vers

U-Boot 2012.07-00125-ged34f34 (Aug 10 2012 - 09:36:33)
powerpc-linux-gcc (GCC) 4.6.4 20120303 (prerelease)
GNU ld (GNU Binutils) 2.22
=> date ; ext2load ide 0:4 100000 usr-bin.tar 2000000 ; date
Date: 2012-08-10 (Saturday)    Time: 16:27:21
Loading file "usr-bin.tar" from ide device 0:4 hda4
33554432 bytes read
Date: 2012-08-10 (Saturday)    Time: 16:27:48

=================================================

27 seconds => 1.2 MiB/s

=> vers

U-Boot 2012.07 (Aug 02 2012 - 10:31:44)
powerpc-linux-gcc (GCC) 4.6.4 20120303 (prerelease)
GNU ld (GNU Binutils) 2.22
=> date ; ext2load ide 0:4 100000 usr-bin.tar 2000000 ; date
Date: 2012-08-10 (Saturday)    Time: 16:49:31
Loading file "usr-bin.tar" from ide device 0:4 (hda4)
33554432 bytes read
Date: 2012-08-10 (Saturday)    Time: 16:49:57

=================================================

26 seconds => 1.2 MiB/s


So within the accuracy of this measurement,the performance of the new
code compared to the old ext2 code appears to be pretty much the same.

Tested-by: Wolfgang Denk <wd@denx.de>

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 at denx.de
Keep your eyes wide open before marriage, half shut afterwards.
                                                 -- Benjamin Franklin

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [U-Boot] [PATCH V5 2/2] ext4fs write support
  2012-08-13 11:55         ` Wolfgang Denk
@ 2012-08-13 13:52           ` uma.shankar at samsung.com
  0 siblings, 0 replies; 14+ messages in thread
From: uma.shankar at samsung.com @ 2012-08-13 13:52 UTC (permalink / raw)
  To: u-boot

Dear Wolfgang,
We have tested this feature on Samsung Boards using mmc interface. Here is a 
sample test run with exactly the same file size which you have used for 
testing

[Mon Aug 13 19:05:51.824 2012]  # ext4load mmc 0:6 0x40007fc0 abc.tar
[Mon Aug 13 19:05:51.846 2012] Loading file "abc.tar" from mmc device 0:6 
(dt)
[Mon Aug 13 19:05:53.087 2012] 33554432 bytes read
[Mon Aug 13 19:05:53.091 2012] #
Time taken 1.267s
=> 25.25 MiB/s

[Mon Aug 13 19:07:35.323 2012] # ext4load mmc 0:6 0x40007fc0 abc.tar
[Mon Aug 13 19:07:35.351 2012] Loading file "abc.tar" from mmc device 0:6 
(dt)
[Mon Aug 13 19:07:36.591 2012] 33554432 bytes read
[Mon Aug 13 19:07:36.595 2012] #
Time taken 1.272s
=> 25.15 MiB/s

I tried to look into ide interface implementation. It seems in case of ide 
(cmd_ide.c), "ide_read" function tries to read block by block.
Whereas in case of mmc interface, it has bulk read implementation where in 
multiple continuous blocks can be read in one shot.

Previous implementation of ext2 relies on block by block read, where as in 
current implementation multiple block read has been used. Thus, we are 
getting slow performance for ide in both the cases.

Note: I am using teraterm timestamp instead of date command to measure time.

Thanks & Regards,
Uma Shankar
--------------------------------------------------
From: "Wolfgang Denk" <wd@denx.de>
Sent: Monday, August 13, 2012 5:25 PM
To: "Uma Shankar" <uma.shankar@samsung.com>
Cc: "Manjunatha C Achar" <a.manjunatha@samsung.com>; 
<kim.phillips@freescale.com>; <u-boot@lists.denx.de>; "Hakgoo Lee" 
<goodguy.lee@samsung.com>; "Iqbal Shareef" <iqbal.ams@samsung.com>
Subject: Re: [U-Boot] [PATCH V5 2/2] ext4fs write support

> Dear Uma Shankar,
>
> In message <20120809215050.89DE220401A@gemini.denx.de> I wrote:
>>
>> Applied to "ext4" branch, thanks.
>
> I did some performance tests on a MPC5200 based board using the IDE
> interface (no DMA):
>
> => vers
>
> U-Boot 2012.07-00125-ged34f34 (Aug 10 2012 - 09:36:33)
> powerpc-linux-gcc (GCC) 4.6.4 20120303 (prerelease)
> GNU ld (GNU Binutils) 2.22
> => date ; ext2load ide 0:4 100000 usr-bin.tar 2000000 ; date
> Date: 2012-08-10 (Saturday)    Time: 16:27:21
> Loading file "usr-bin.tar" from ide device 0:4 hda4
> 33554432 bytes read
> Date: 2012-08-10 (Saturday)    Time: 16:27:48
>
> =================================================
>
> 27 seconds => 1.2 MiB/s
>
> => vers
>
> U-Boot 2012.07 (Aug 02 2012 - 10:31:44)
> powerpc-linux-gcc (GCC) 4.6.4 20120303 (prerelease)
> GNU ld (GNU Binutils) 2.22
> => date ; ext2load ide 0:4 100000 usr-bin.tar 2000000 ; date
> Date: 2012-08-10 (Saturday)    Time: 16:49:31
> Loading file "usr-bin.tar" from ide device 0:4 (hda4)
> 33554432 bytes read
> Date: 2012-08-10 (Saturday)    Time: 16:49:57
>
> =================================================
>
> 26 seconds => 1.2 MiB/s
>
>
> So within the accuracy of this measurement,the performance of the new
> code compared to the old ext2 code appears to be pretty much the same.
>
> Tested-by: Wolfgang Denk <wd@denx.de>
>
> 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 at denx.de
> Keep your eyes wide open before marriage, half shut afterwards.
>                                                 -- Benjamin Franklin 

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2012-08-13 13:52 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-12-15 17:39 [U-Boot] [PATCH 2/2] ext4fs write support uma.shankar at samsung.com
2011-12-15 22:20 ` Kim Phillips
2011-12-16 16:10 ` Mike Frysinger
2011-12-28  2:23 ` [U-Boot] [PATCH V3 " uma.shankar at samsung.com
2012-01-05 15:25   ` Wolfgang Denk
2012-01-08  4:24   ` Mike Frysinger
2012-01-09 17:56   ` [U-Boot] [PATCH V4 " uma.shankar at samsung.com
2012-01-16  0:03     ` Mike Frysinger
2012-01-16  7:58       ` Wolfgang Denk
2012-01-16 10:06         ` Mike Frysinger
2012-05-25 15:52     ` [U-Boot] [PATCH V5 " Uma Shankar
2012-08-09 21:50       ` Wolfgang Denk
2012-08-13 11:55         ` Wolfgang Denk
2012-08-13 13:52           ` uma.shankar at samsung.com

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.