Index: uspace/lib/ext4/libext4.h
===================================================================
--- uspace/lib/ext4/libext4.h	(revision bf66ef4449472db94d23f414adce9ea2a7577ff4)
+++ uspace/lib/ext4/libext4.h	(revision 3d4fd2c9ea020e433ba976899d9cdf98ee83a800)
@@ -42,4 +42,5 @@
 #include "libext4_filesystem.h"
 #include "libext4_hash.h"
+#include "libext4_ialloc.h"
 #include "libext4_inode.h"
 #include "libext4_superblock.h"
Index: uspace/lib/ext4/libext4_filesystem.c
===================================================================
--- uspace/lib/ext4/libext4_filesystem.c	(revision bf66ef4449472db94d23f414adce9ea2a7577ff4)
+++ uspace/lib/ext4/libext4_filesystem.c	(revision 3d4fd2c9ea020e433ba976899d9cdf98ee83a800)
@@ -283,4 +283,174 @@
 }
 
+int ext4_filesystem_free_inode(ext4_filesystem_t *fs, ext4_inode_ref_t *inode_ref)
+{
+	int rc;
+	// release all indirect blocks
+
+	uint32_t fblock;
+
+	// 1) Single indirect
+	fblock = ext4_inode_get_indirect_block(inode_ref->inode, 0);
+	if (fblock != 0) {
+		rc = ext4_balloc_free_block(fs, inode_ref, fblock);
+		if (rc != EOK) {
+			// TODO error
+		}
+
+		ext4_inode_set_indirect_block(inode_ref->inode, 0, 0);
+	}
+
+	block_t *block;
+	uint32_t block_size = ext4_superblock_get_block_size(fs->superblock);
+	uint32_t count = block_size / sizeof(uint32_t);
+
+	// 2) Double indirect
+	fblock = ext4_inode_get_indirect_block(inode_ref->inode, 1);
+	if (fblock != 0) {
+		rc = block_get(&block, fs->device, fblock, BLOCK_FLAGS_NONE);
+		if (rc != EOK) {
+			// TODO error
+		}
+
+		uint32_t ind_block;
+		for (uint32_t offset = 0; offset < count; ++offset) {
+			ind_block = uint32_t_le2host(((uint32_t*)block->data)[offset]);
+
+			if (ind_block != 0) {
+				rc = ext4_balloc_free_block(fs, inode_ref, ind_block);
+				if (rc != EOK) {
+					// TODO error
+				}
+			}
+		}
+
+		block_put(block);
+		rc = ext4_balloc_free_block(fs, inode_ref, fblock);
+		if (rc != EOK) {
+			// TODO error
+		}
+
+		ext4_inode_set_indirect_block(inode_ref->inode, 1, 0);
+	}
+
+
+	// 3) Tripple indirect
+	block_t *subblock;
+	fblock = ext4_inode_get_indirect_block(inode_ref->inode, 2);
+	if (fblock != 0) {
+		rc = block_get(&block, fs->device, fblock, BLOCK_FLAGS_NONE);
+		if (rc != EOK) {
+			// TODO error
+		}
+
+		uint32_t ind_block;
+		for (uint32_t offset = 0; offset < count; ++offset) {
+			ind_block = uint32_t_le2host(((uint32_t*)block->data)[offset]);
+
+			if (ind_block != 0) {
+				rc = block_get(&subblock, fs->device, ind_block, BLOCK_FLAGS_NONE);
+				if (rc != EOK) {
+					// TODO error
+				}
+
+				uint32_t ind_subblock;
+				for (uint32_t suboffset = 0; suboffset < count; ++suboffset) {
+					ind_subblock = uint32_t_le2host(((uint32_t*)subblock->data)[suboffset]);
+
+					if (ind_subblock != 0) {
+						rc = ext4_balloc_free_block(fs, inode_ref, ind_subblock);
+						if (rc != EOK) {
+							// TODO error
+						}
+					}
+
+				}
+				block_put(subblock);
+
+			}
+
+			rc = ext4_balloc_free_block(fs, inode_ref, ind_block);
+			if (rc != EOK) {
+				// TODO error
+			}
+
+
+		}
+
+		block_put(block);
+		rc = ext4_balloc_free_block(fs, inode_ref, fblock);
+		if (rc != EOK) {
+			// TODO error
+		}
+
+		ext4_inode_set_indirect_block(inode_ref->inode, 2, 0);
+	}
+
+	// Free inode
+	rc = ext4_ialloc_free_inode(fs, inode_ref);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	return EOK;
+}
+
+int ext4_filesystem_truncate_inode(ext4_filesystem_t *fs,
+		ext4_inode_ref_t *inode_ref, aoff64_t new_size)
+{
+	aoff64_t old_size;
+	aoff64_t size_diff;
+
+	if (! ext4_inode_can_truncate(fs->superblock, inode_ref->inode)) {
+		// Unable to truncate
+		return EINVAL;
+	}
+
+	old_size = ext4_inode_get_size(fs->superblock, inode_ref->inode);
+
+	if (old_size == new_size) {
+		// Nothing to do
+		return EOK;
+	}
+
+	uint32_t block_size;
+	uint32_t blocks_count, total_blocks;
+	uint32_t i;
+
+	block_size  = ext4_superblock_get_block_size(fs->superblock);
+
+	if (old_size < new_size) {
+		// Currently not supported to expand the file
+		// TODO
+		EXT4FS_DBG("trying to expand the file");
+		return EINVAL;
+	}
+
+	size_diff = old_size - new_size;
+	blocks_count = size_diff / block_size;
+	if (size_diff % block_size != 0) {
+		blocks_count++;
+	}
+
+	total_blocks = old_size / block_size;
+	if (old_size % block_size != 0) {
+		total_blocks++;
+	}
+
+	// starting from 1 because of logical blocks are numbered from 0
+	for (i = 1; i <= blocks_count; ++i) {
+		// TODO check retval
+		// TODO decrement inode->blocks_count
+
+		ext4_filesystem_release_inode_block(fs, inode_ref, total_blocks - i);
+	}
+
+	ext4_inode_set_size(inode_ref->inode, new_size);
+
+	inode_ref->dirty = true;
+
+	return EOK;
+}
+
 int ext4_filesystem_get_inode_data_block_index(ext4_filesystem_t *fs, ext4_inode_t* inode,
     aoff64_t iblock, uint32_t* fblock)
Index: uspace/lib/ext4/libext4_filesystem.h
===================================================================
--- uspace/lib/ext4/libext4_filesystem.h	(revision bf66ef4449472db94d23f414adce9ea2a7577ff4)
+++ uspace/lib/ext4/libext4_filesystem.h	(revision 3d4fd2c9ea020e433ba976899d9cdf98ee83a800)
@@ -61,4 +61,7 @@
 		ext4_inode_ref_t **);
 extern int ext4_filesystem_put_inode_ref(ext4_inode_ref_t *);
+extern int ext4_filesystem_free_inode(ext4_filesystem_t *, ext4_inode_ref_t *);
+extern int ext4_filesystem_truncate_inode(ext4_filesystem_t *,
+		ext4_inode_ref_t *, aoff64_t);
 extern int ext4_filesystem_get_inode_data_block_index(ext4_filesystem_t *,
 	ext4_inode_t *, aoff64_t iblock, uint32_t *);
Index: uspace/lib/ext4/libext4_ialloc.c
===================================================================
--- uspace/lib/ext4/libext4_ialloc.c	(revision bf66ef4449472db94d23f414adce9ea2a7577ff4)
+++ uspace/lib/ext4/libext4_ialloc.c	(revision 3d4fd2c9ea020e433ba976899d9cdf98ee83a800)
@@ -36,5 +36,80 @@
  */
 
+#include <errno.h>
 #include "libext4.h"
+
+static uint32_t ext4_ialloc_inode2index_in_group(ext4_superblock_t *sb,
+		uint32_t inode)
+{
+	uint32_t inodes_per_group = ext4_superblock_get_inodes_per_group(sb);
+	return (inode - 1) % inodes_per_group;
+}
+
+static uint32_t ext4_ialloc_get_bgid_of_inode(ext4_superblock_t *sb,
+		uint32_t inode)
+{
+	uint32_t inodes_per_group = ext4_superblock_get_inodes_per_group(sb);
+	return (inode - 1) / inodes_per_group;
+
+}
+
+
+int ext4_ialloc_free_inode(ext4_filesystem_t *fs, ext4_inode_ref_t *inode_ref)
+{
+	int rc;
+	uint32_t block_group = ext4_ialloc_get_bgid_of_inode(
+			fs->superblock, inode_ref->index);
+	uint32_t index_in_group = ext4_ialloc_inode2index_in_group(
+			fs->superblock, inode_ref->index);
+
+	ext4_block_group_ref_t *bg_ref;
+	rc = ext4_filesystem_get_block_group_ref(fs, block_group, &bg_ref);
+	if (rc != EOK) {
+		EXT4FS_DBG("error in loading bg_ref \%d", rc);
+		return rc;
+	}
+
+	uint32_t bitmap_block_addr = ext4_block_group_get_inode_bitmap(
+			bg_ref->block_group, fs->superblock);
+	block_t *bitmap_block;
+	rc = block_get(&bitmap_block, fs->device, bitmap_block_addr, 0);
+	if (rc != EOK) {
+		EXT4FS_DBG("error in loading bitmap \%d", rc);
+		return rc;
+	}
+
+	ext4_bitmap_free_bit(bitmap_block->data, index_in_group);
+	bitmap_block->dirty = true;
+
+	rc = block_put(bitmap_block);
+	if (rc != EOK) {
+		// Error in saving bitmap
+		ext4_filesystem_put_block_group_ref(bg_ref);
+		EXT4FS_DBG("error in saving bitmap \%d", rc);
+		return rc;
+	}
+
+	// Update superblock free inodes count
+	uint32_t sb_free_inodes = ext4_superblock_get_free_inodes_count(fs->superblock);
+	sb_free_inodes--;
+	ext4_superblock_set_free_inodes_count(fs->superblock, sb_free_inodes);
+
+	// Update block group free inodes count
+	uint32_t free_inodes = ext4_block_group_get_free_inodes_count(
+			bg_ref->block_group, fs->superblock);
+	free_inodes++;
+	ext4_block_group_set_free_inodes_count(bg_ref->block_group,
+			fs->superblock, free_inodes);
+	bg_ref->dirty = true;
+
+	rc = ext4_filesystem_put_block_group_ref(bg_ref);
+	if (rc != EOK) {
+		EXT4FS_DBG("error in saving bg_ref \%d", rc);
+		// TODO error
+		return rc;
+	}
+
+	return EOK;
+}
 
 
Index: uspace/lib/ext4/libext4_ialloc.h
===================================================================
--- uspace/lib/ext4/libext4_ialloc.h	(revision bf66ef4449472db94d23f414adce9ea2a7577ff4)
+++ uspace/lib/ext4/libext4_ialloc.h	(revision 3d4fd2c9ea020e433ba976899d9cdf98ee83a800)
@@ -34,4 +34,8 @@
 #define LIBEXT4_LIBEXT4_IALLOC_H_
 
+#include "libext4_filesystem.h"
+#include "libext4_inode.h"
+
+extern int ext4_ialloc_free_inode(ext4_filesystem_t *, ext4_inode_ref_t *);
 
 #endif
Index: uspace/srv/fs/ext4fs/ext4fs_ops.c
===================================================================
--- uspace/srv/fs/ext4fs/ext4fs_ops.c	(revision bf66ef4449472db94d23f414adce9ea2a7577ff4)
+++ uspace/srv/fs/ext4fs/ext4fs_ops.c	(revision 3d4fd2c9ea020e433ba976899d9cdf98ee83a800)
@@ -382,4 +382,49 @@
 int ext4fs_destroy_node(fs_node_t *fn)
 {
+	int rc;
+
+	bool has_children;
+	rc = ext4fs_has_children(&has_children, fn);
+	if (rc != EOK) {
+		ext4fs_node_put(fn);
+		return rc;
+	}
+
+	if (has_children) {
+		EXT4FS_DBG("destroying non-empty node");
+		ext4fs_node_put(fn);
+		return EINVAL;
+	}
+
+	ext4fs_node_t *enode = EXT4FS_NODE(fn);
+	ext4_filesystem_t *fs = enode->instance->filesystem;
+	ext4_inode_ref_t *inode_ref = enode->inode_ref;
+
+	EXT4FS_DBG("destroying \%u", inode_ref->index);
+
+	rc = ext4_filesystem_truncate_inode(fs, inode_ref, 0);
+	if (rc != EOK) {
+		ext4fs_node_put(fn);
+		return rc;
+	}
+
+	rc = ext4_filesystem_free_inode(fs, inode_ref);
+	if (rc != EOK) {
+		ext4fs_node_put(fn);
+		return rc;
+	}
+
+	ext4fs_node_put(fn);
+	return EOK;
+
+//	EXT4FS_DBG("not supported");
+//
+//	// TODO
+//	return ENOTSUP;
+}
+
+
+int ext4fs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
+{
 	EXT4FS_DBG("not supported");
 
@@ -389,15 +434,8 @@
 
 
-int ext4fs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
-{
-	EXT4FS_DBG("not supported");
-
-	// TODO
-	return ENOTSUP;
-}
-
-
 int ext4fs_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *name)
 {
+	EXT4FS_DBG("unlinking \%s", name);
+
 	int rc;
 
@@ -430,14 +468,27 @@
 	child_inode_ref->dirty = true;
 
+//	EXT4FS_DBG("links count = \%u", lnk_count);
+
 	// If directory - handle links from parent
 	if (lnk_count <= 1 && ext4fs_is_directory(cfn)) {
 
-		ext4_inode_ref_t *parent_inode_ref = EXT4FS_NODE(pfn)->inode_ref;
-		uint32_t parent_lnk_count = ext4_inode_get_links_count(
-				parent_inode_ref->inode);
-		parent_lnk_count--;
-		ext4_inode_set_links_count(parent_inode_ref->inode, parent_lnk_count);
-
-		parent_inode_ref->dirty = true;
+//		EXT4FS_DBG("directory will be removed, lnlk_count = \%u", lnk_count);
+
+		if (lnk_count) {
+			lnk_count = ext4_inode_get_links_count(child_inode_ref->inode);
+			lnk_count--;
+			ext4_inode_set_links_count(child_inode_ref->inode, lnk_count);
+		}
+
+//		ext4_inode_ref_t *parent_inode_ref = EXT4FS_NODE(pfn)->inode_ref;
+//		uint32_t parent_lnk_count = ext4_inode_get_links_count(
+//				parent_inode_ref->inode);
+//
+//		EXT4FS_DBG("directory will be removed, parent link count = \%u", parent_lnk_count);
+//
+//		parent_lnk_count--;
+//		ext4_inode_set_links_count(parent_inode_ref->inode, parent_lnk_count);
+//
+//		parent_inode_ref->dirty = true;
 	}
 
@@ -1021,11 +1072,8 @@
 ext4fs_truncate(service_id_t service_id, fs_index_t index, aoff64_t new_size)
 {
+	int rc;
 	fs_node_t *fn;
-	ext4fs_node_t *enode;
-	ext4_inode_ref_t *inode_ref;
-	ext4_filesystem_t* fs;
-	aoff64_t old_size;
-	aoff64_t size_diff;
-	int rc;
+//	aoff64_t old_size;
+//	aoff64_t size_diff;
 
 	rc = ext4fs_node_get(&fn, service_id, index);
@@ -1034,63 +1082,68 @@
 	}
 
-	enode = EXT4FS_NODE(fn);
-	inode_ref = enode->inode_ref;
-	fs = enode->instance->filesystem;
-
-
-	if (! ext4_inode_can_truncate(fs->superblock, inode_ref->inode)) {
-		// Unable to truncate
-		ext4fs_node_put(fn);
-		return EINVAL;
-	}
-
-	old_size = ext4_inode_get_size(fs->superblock, inode_ref->inode);
-
-	if (old_size == new_size) {
-		ext4fs_node_put(fn);
-		return EOK;
-	} else {
-
-		uint32_t block_size;
-		uint32_t blocks_count, total_blocks;
-		uint32_t i;
-
-		block_size  = ext4_superblock_get_block_size(fs->superblock);
-
-		if (old_size < new_size) {
-			// Currently not supported to expand the file
-			// TODO
-			EXT4FS_DBG("trying to expand the file");
-			return EINVAL;
-		}
-
-		size_diff = old_size - new_size;
-		blocks_count = size_diff / block_size;
-		if (size_diff % block_size != 0) {
-			blocks_count++;
-		}
-
-		total_blocks = old_size / block_size;
-		if (old_size % block_size != 0) {
-			total_blocks++;
-		}
-
-		inode_ref->dirty = true;
-
-		// starting from 1 because of logical blocks are numbered from 0
-		for (i = 1; i <= blocks_count; ++i) {
-			// TODO check retval
-			// TODO decrement inode->blocks_count
-
-			ext4_filesystem_release_inode_block(fs, inode_ref, total_blocks - i);
-		}
-
-		ext4_inode_set_size(inode_ref->inode, new_size);
-
-	}
-
+	ext4fs_node_t *enode = EXT4FS_NODE(fn);
+	ext4_inode_ref_t *inode_ref = enode->inode_ref;
+	ext4_filesystem_t *fs = enode->instance->filesystem;
+
+	rc = ext4_filesystem_truncate_inode(fs, inode_ref, new_size);
 	ext4fs_node_put(fn);
 
-	return EOK;
+	return rc;
+
+//	if (! ext4_inode_can_truncate(fs->superblock, inode_ref->inode)) {
+//		// Unable to truncate
+//		ext4fs_node_put(fn);
+//		return EINVAL;
+//	}
+//
+//	old_size = ext4_inode_get_size(fs->superblock, inode_ref->inode);
+//
+//	if (old_size == new_size) {
+//		ext4fs_node_put(fn);
+//		return EOK;
+//	} else {
+//
+//		uint32_t block_size;
+//		uint32_t blocks_count, total_blocks;
+//		uint32_t i;
+//
+//		block_size  = ext4_superblock_get_block_size(fs->superblock);
+//
+//		if (old_size < new_size) {
+//			// Currently not supported to expand the file
+//			// TODO
+//			EXT4FS_DBG("trying to expand the file");
+//			ext4fs_node_put(fn);
+//			return EINVAL;
+//		}
+//
+//		size_diff = old_size - new_size;
+//		blocks_count = size_diff / block_size;
+//		if (size_diff % block_size != 0) {
+//			blocks_count++;
+//		}
+//
+//		total_blocks = old_size / block_size;
+//		if (old_size % block_size != 0) {
+//			total_blocks++;
+//		}
+//
+//		// starting from 1 because of logical blocks are numbered from 0
+//		for (i = 1; i <= blocks_count; ++i) {
+//			// TODO check retval
+//			// TODO decrement inode->blocks_count
+//
+//			ext4_filesystem_release_inode_block(fs, inode_ref, total_blocks - i);
+//		}
+//
+//		ext4_inode_set_size(inode_ref->inode, new_size);
+//
+//		inode_ref->dirty = true;
+//
+//	}
+//
+//	ext4fs_node_put(fn);
+//
+//	return EOK;
 }
 
