Index: uspace/lib/ext4/libext4_balloc.c
===================================================================
--- uspace/lib/ext4/libext4_balloc.c	(revision e18de3c4ff73329ab91e81d578f312420d58e025)
+++ uspace/lib/ext4/libext4_balloc.c	(revision b12ca161211cc9652a5fedaf484bf00025c12c06)
@@ -31,52 +31,89 @@
  */ 
 
+/**
+ * @file	libext4_balloc.c
+ * @brief	Block allocator.
+ */
+
 #include <errno.h>
 #include <sys/types.h>
 #include "libext4.h"
 
-int ext4_bitmap_free_block(ext4_filesystem_t *fs, ext4_inode_ref_t *inode_ref, uint32_t block_index)
-{
-	int rc;
-	uint32_t blocks_per_group;
-	uint32_t block_group;
-	uint32_t index_in_group;
-	uint32_t bitmap_block;
-	uint32_t block_size;
-	ext4_block_group_ref_t *bg_ref;
-	block_t *block;
-	uint32_t first_block;
-
-	block_size = ext4_superblock_get_block_size(fs->superblock);
-	blocks_per_group = ext4_superblock_get_blocks_per_group(fs->superblock);
-	first_block = ext4_superblock_get_first_data_block(fs->superblock);
+static uint32_t ext4_balloc_blockaddr2_index_in_group(ext4_superblock_t *sb,
+		uint32_t block_addr)
+{
+	uint32_t blocks_per_group = ext4_superblock_get_blocks_per_group(sb);
+	uint32_t first_block = ext4_superblock_get_first_data_block(sb);
 
 	// First block == 0 or 1
 	if (first_block == 0) {
-		block_group = block_index / blocks_per_group;
-		index_in_group = block_index % blocks_per_group;
+		return block_addr % blocks_per_group;
 	} else {
-		block_group = (block_index - 1) / blocks_per_group;
-		index_in_group = (block_index - 1) % blocks_per_group;
-	}
-
+		return (block_addr - 1) % blocks_per_group;
+	}
+}
+
+static uint32_t ext4_balloc_index_in_group2blockaddr(ext4_superblock_t *sb,
+		uint32_t index, uint32_t bgid)
+{
+	uint32_t blocks_per_group = ext4_superblock_get_blocks_per_group(sb);
+
+	if (ext4_superblock_get_first_data_block(sb) == 0) {
+		return bgid * blocks_per_group + index;
+	} else {
+		return bgid * blocks_per_group + index + 1;
+	}
+
+}
+
+static uint32_t ext4_balloc_get_bgid_of_block(ext4_superblock_t *sb,
+		uint32_t block_addr)
+{
+	uint32_t blocks_per_group = ext4_superblock_get_blocks_per_group(sb);
+	uint32_t first_block = ext4_superblock_get_first_data_block(sb);
+
+	// First block == 0 or 1
+	if (first_block == 0) {
+		return block_addr / blocks_per_group;
+	} else {
+		return (block_addr - 1) / blocks_per_group;
+	}
+}
+
+
+int ext4_balloc_free_block(ext4_filesystem_t *fs, ext4_inode_ref_t *inode_ref, uint32_t block_addr)
+{
+	int rc;
+
+	uint32_t block_group = ext4_balloc_get_bgid_of_block(fs->superblock, block_addr);
+	uint32_t index_in_group = ext4_balloc_blockaddr2_index_in_group(fs->superblock, block_addr);
+
+	ext4_block_group_ref_t *bg_ref;
 	rc = ext4_filesystem_get_block_group_ref(fs, block_group, &bg_ref);
 	if (rc != EOK) {
-		return rc;
-	}
-
-	bitmap_block = ext4_block_group_get_block_bitmap(bg_ref->block_group);
-
-	rc = block_get(&block, fs->device, bitmap_block, 0);
-	if (rc != EOK) {
-		return rc;
-	}
-
-	ext4_bitmap_free_bit(block->data, index_in_group);
-
-	block->dirty = true;
-	rc = block_put(block);
-	if (rc != EOK) {
-		return rc;
-	}
+		EXT4FS_DBG("error in loading bg_ref \%d", rc);
+		return rc;
+	}
+
+	uint32_t bitmap_block_addr = ext4_block_group_get_block_bitmap(bg_ref->block_group);
+	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;
+	}
+
+	uint32_t block_size = ext4_superblock_get_block_size(fs->superblock);
 
 	uint64_t ino_blocks = ext4_inode_get_blocks_count(fs->superblock, inode_ref->inode);
@@ -99,18 +136,47 @@
 	}
 
+//	EXT4FS_DBG("released block \%u (idx = \%u)", block_addr, index_in_group);
 	return EOK;
 }
 
-
-static uint32_t ext4_bitmap_find_goal(ext4_filesystem_t *fs, ext4_inode_ref_t *inode_ref)
-{
+static uint32_t ext4_balloc_get_first_data_block_in_group(
+		ext4_superblock_t *sb, ext4_block_group_t *bg, uint32_t bgid)
+{
+	uint32_t block_group_count = ext4_superblock_get_block_group_count(sb);
+	uint32_t inode_table_first_block = ext4_block_group_get_inode_table_first_block(bg);
+	uint16_t inode_table_item_size = ext4_superblock_get_inode_size(sb);
+	uint32_t inodes_per_group = ext4_superblock_get_inodes_per_group(sb);
+	uint32_t block_size = ext4_superblock_get_block_size(sb);
+	uint32_t inode_table_bytes;
+
+	if (bgid < block_group_count - 1) {
+		inode_table_bytes = inodes_per_group * inode_table_item_size;
+	} else {
+		// last block group could be smaller
+		uint32_t inodes_count_total = ext4_superblock_get_inodes_count(sb);
+		inode_table_bytes =
+				(inodes_count_total - ((block_group_count - 1) * inodes_per_group))
+				* inode_table_item_size;
+	}
+
+	uint32_t inode_table_blocks = inode_table_bytes / block_size;
+
+	if (inode_table_bytes % block_size) {
+		inode_table_blocks++;
+	}
+
+	return inode_table_first_block + inode_table_blocks;
+}
+
+
+static uint32_t ext4_balloc_find_goal(ext4_filesystem_t *fs, ext4_inode_ref_t *inode_ref)
+{
+	int rc;
 	uint32_t goal = 0;
 
-	int rc;
 	uint64_t inode_size = ext4_inode_get_size(fs->superblock, inode_ref->inode);
 	uint32_t block_size = ext4_superblock_get_block_size(fs->superblock);
 	uint32_t inode_block_count = inode_size / block_size;
 
-
 	if (inode_size % block_size != 0) {
 		inode_block_count++;
@@ -119,14 +185,17 @@
 	if (inode_block_count > 0) {
 		// TODO check retval
-//		EXT4FS_DBG("has blocks");
 		ext4_filesystem_get_inode_data_block_index(fs, inode_ref->inode, inode_block_count - 1, &goal);
 
 		// TODO
 		// If goal == 0 -> SPARSE file !!!
+
 		goal++;
+
+//		EXT4FS_DBG("goal = \%u, inode_block_count == \%u", goal, inode_block_count);
+
 		return goal;
 	}
 
-//	uint32_t blocks_per_group = ext4_superblock_get_blocks_per_group(fs->superblock);
+//	EXT4FS_DBG("Inode has no blocks");
 
 	// Identify block group of inode
@@ -141,7 +210,19 @@
 	}
 
+	uint32_t block_group_count = ext4_superblock_get_block_group_count(fs->superblock);
 	uint32_t inode_table_first_block = ext4_block_group_get_inode_table_first_block(bg_ref->block_group);
 	uint16_t inode_table_item_size = ext4_superblock_get_inode_size(fs->superblock);
-	uint32_t inode_table_bytes = inodes_per_group * inode_table_item_size;
+	uint32_t inode_table_bytes;
+
+	if (block_group < block_group_count - 1) {
+		inode_table_bytes = inodes_per_group * inode_table_item_size;
+	} else {
+		// last block group could be smaller
+		uint32_t inodes_count_total = ext4_superblock_get_inodes_count(fs->superblock);
+		inode_table_bytes =
+				(inodes_count_total - ((block_group_count - 1) * inodes_per_group))
+				* inode_table_item_size;
+	}
+
 	uint32_t inode_table_blocks = inode_table_bytes / block_size;
 
@@ -157,49 +238,41 @@
 }
 
-int ext4_bitmap_alloc_block(ext4_filesystem_t *fs, ext4_inode_ref_t *inode_ref, uint32_t *fblock)
+int ext4_balloc_alloc_block(ext4_filesystem_t *fs, ext4_inode_ref_t *inode_ref, uint32_t *fblock)
 {
 	int rc;
-	ext4_block_group_ref_t *bg_ref;
+	uint32_t allocated_block = 0;
+
 	uint32_t bitmap_block;
 	block_t *block;
 	uint32_t rel_block_idx = 0;
-	uint32_t index_in_group;
-	uint32_t tmp;
-
-	uint32_t allocated_block = 0;
-
-	// Determine GOAL
-	uint32_t goal = ext4_bitmap_find_goal(fs, inode_ref);
-
-	uint32_t block_size = ext4_superblock_get_block_size(fs->superblock);
-
-	//if (goal == 0) - unable to determine goal
+
+	// Find GOAL
+	uint32_t goal = ext4_balloc_find_goal(fs, inode_ref);
 	if (goal == 0) {
 		// TODO
 		EXT4FS_DBG("ERRORR (goal == 0)");
-	}
-
-//	EXT4FS_DBG("goal = \%u", goal);
-
-	uint32_t blocks_per_group = ext4_superblock_get_blocks_per_group(fs->superblock);
-	uint32_t first_block = ext4_superblock_get_first_data_block(fs->superblock);
-
-	uint32_t block_group;
-
-	// First block == 0 or 1
-	if (first_block == 0) {
-		block_group = goal / blocks_per_group;
-		index_in_group = goal % blocks_per_group;
-	} else {
-		block_group = (goal - 1) / blocks_per_group;
-		index_in_group = (goal - 1) % blocks_per_group;
-	}
-
-
+		return ENOSPC;
+	}
+
+	// Load block group number for goal and relative index
+	uint32_t block_group = ext4_balloc_get_bgid_of_block(fs->superblock, goal);
+	uint32_t index_in_group = ext4_balloc_blockaddr2_index_in_group(fs->superblock, goal);
 //	EXT4FS_DBG("block_group = \%u, index_in_group = \%u", block_group, index_in_group);
 
+
+
+	ext4_block_group_ref_t *bg_ref;
 	rc = ext4_filesystem_get_block_group_ref(fs, block_group, &bg_ref);
 	if (rc != EOK) {
-		return rc;
+		EXT4FS_DBG("initial BG ref not loaded");
+		return rc;
+	}
+
+	uint32_t first_in_group =
+			ext4_balloc_get_first_data_block_in_group(fs->superblock,
+					bg_ref->block_group, block_group);
+
+	if (index_in_group < first_in_group) {
+		index_in_group = first_in_group;
 	}
 
@@ -210,4 +283,5 @@
 	if (rc != EOK) {
 		ext4_filesystem_put_block_group_ref(bg_ref);
+		EXT4FS_DBG("initial bitmap not loaded");
 		return rc;
 	}
@@ -215,8 +289,6 @@
 //	EXT4FS_DBG("bitmap loaded");
 
+	// Check if goal is free
 	if (ext4_bitmap_is_free_bit(block->data, index_in_group)) {
-
-//		EXT4FS_DBG("goal is free");
-
 		ext4_bitmap_set_bit(block->data, index_in_group);
 		block->dirty = true;
@@ -224,23 +296,125 @@
 		if (rc != EOK) {
 			// TODO error
-			EXT4FS_DBG("error in saving bitmap \%d", rc);
+			EXT4FS_DBG("goal check: error in saving initial bitmap \%d", rc);
+			ext4_filesystem_put_block_group_ref(bg_ref);
+			return rc;
 		}
 
 		allocated_block = goal;
-		goto end;
-
-	}
-
-//	EXT4FS_DBG("try 63 blocks after goal");
+		goto success;
+
+	}
+
+	uint32_t blocks_in_group = ext4_superblock_get_blocks_in_group(fs->superblock, block_group);
+
+//	EXT4FS_DBG("index = \%u (goal = \%u), blocks_in_group = \%u", index_in_group, goal, blocks_in_group);
+
+	uint32_t end_idx = (index_in_group + 63) & ~63;
+	if (end_idx > blocks_in_group) {
+		end_idx = blocks_in_group;
+	}
+
 	// Try to find free block near to goal
-	for (tmp = index_in_group + 1; (tmp < blocks_per_group) && (tmp < ((index_in_group + 63) & ~63)); ++tmp) {
-
-//		EXT4FS_DBG("trying \%u", tmp);
-
-		if (ext4_bitmap_is_free_bit(block->data, tmp)) {
-
-//			EXT4FS_DBG("block \%u is free -> allocate it", tmp);
-
-			ext4_bitmap_set_bit(block->data, tmp);
+	for (uint32_t tmp_idx = index_in_group + 1; tmp_idx < end_idx; ++tmp_idx) {
+		if (ext4_bitmap_is_free_bit(block->data, tmp_idx)) {
+
+			ext4_bitmap_set_bit(block->data, tmp_idx);
+			block->dirty = true;
+			rc = block_put(block);
+			if (rc != EOK) {
+				// TODO error
+				EXT4FS_DBG("near blocks: error in saving initial bitmap \%d", rc);
+			}
+
+			allocated_block = ext4_balloc_index_in_group2blockaddr(
+					fs->superblock, tmp_idx, block_group);
+
+
+//			EXT4FS_DBG("block \%u (idx = \%u) allocated, goal = \%u", allocated_block, tmp_idx, goal);
+
+			goto success;
+		}
+
+	}
+
+	// Find free BYTE in bitmap
+//	EXT4FS_DBG("try find free byte in own BG");
+	rc = ext4_bitmap_find_free_byte_and_set_bit(block->data, index_in_group, &rel_block_idx, blocks_in_group);
+	if (rc == EOK) {
+		block->dirty = true;
+		rc = block_put(block);
+		if (rc != EOK) {
+			// TODO error
+			EXT4FS_DBG("free byte: error in saving initial bitmap \%d", rc);
+		}
+
+		allocated_block = ext4_balloc_index_in_group2blockaddr(
+				fs->superblock, rel_block_idx, block_group);
+
+//		EXT4FS_DBG("block \%u allocated, index = \%u, goal = \%u", allocated_block, rel_block_idx, goal);
+
+		goto success;
+	}
+
+	// Find free bit in bitmap
+	EXT4FS_DBG("find free bit");
+	rc = ext4_bitmap_find_free_bit_and_set(block->data, index_in_group, &rel_block_idx, blocks_in_group);
+	if (rc == EOK) {
+		block->dirty = true;
+		rc = block_put(block);
+		if (rc != EOK) {
+			// TODO error
+			EXT4FS_DBG("free bit: error in saving initial bitmap \%d", rc);
+		}
+
+		allocated_block = ext4_balloc_index_in_group2blockaddr(
+				fs->superblock, rel_block_idx, block_group);
+
+		EXT4FS_DBG("find free bit: block \%u allocated, index = \%u, goal = \%u", allocated_block, rel_block_idx, goal);
+
+		goto success;
+	}
+
+	block_put(block);
+	ext4_filesystem_put_block_group_ref(bg_ref);
+
+	// Try other block groups
+	uint32_t block_group_count = ext4_superblock_get_block_group_count(fs->superblock);
+
+	uint32_t bgid = (block_group + 1) % block_group_count;
+	uint32_t count = block_group_count;
+
+	while (count > 0) {
+		EXT4FS_DBG("trying group \%u", bgid);
+
+		rc = ext4_filesystem_get_block_group_ref(fs, bgid, &bg_ref);
+		if (rc != EOK) {
+			EXT4FS_DBG("errrrrrrrrrrr");
+			return rc;
+		}
+
+		// Load bitmap
+		bitmap_block = ext4_block_group_get_block_bitmap(bg_ref->block_group);
+
+		rc = block_get(&block, fs->device, bitmap_block, 0);
+		if (rc != EOK) {
+			ext4_filesystem_put_block_group_ref(bg_ref);
+			EXT4FS_DBG("errrrrrrrrrr");
+			return rc;
+		}
+
+		first_in_group = ext4_balloc_get_first_data_block_in_group(
+				fs->superblock, bg_ref->block_group, bgid);
+		index_in_group = ext4_balloc_blockaddr2_index_in_group(fs->superblock,
+						first_in_group);
+		blocks_in_group = ext4_superblock_get_blocks_in_group(fs->superblock, bgid);
+
+		if (index_in_group < first_in_group) {
+			index_in_group = first_in_group;
+		}
+
+//		EXT4FS_DBG("trying free byte in bg \%u", bgid);
+		rc = ext4_bitmap_find_free_byte_and_set_bit(block->data, index_in_group, &rel_block_idx, blocks_in_group);
+		if (rc == EOK) {
 			block->dirty = true;
 			rc = block_put(block);
@@ -250,65 +424,48 @@
 			}
 
-			if (first_block == 0) {
-				allocated_block = blocks_per_group * block_group + tmp;
-			} else {
-				allocated_block = blocks_per_group * block_group + tmp + 1;
+			allocated_block = ext4_balloc_index_in_group2blockaddr(
+					fs->superblock, rel_block_idx, bgid);
+
+			EXT4FS_DBG("byte: block \%u allocated, index = \%u, goal = \%u", allocated_block, rel_block_idx, goal);
+
+			goto success;
+		}
+
+		// Find free bit in bitmap
+		rc = ext4_bitmap_find_free_bit_and_set(block->data, index_in_group, &rel_block_idx, blocks_in_group);
+//		EXT4FS_DBG("trying free bit in bg \%u", bgid);
+		if (rc == EOK) {
+			block->dirty = true;
+			rc = block_put(block);
+			if (rc != EOK) {
+				// TODO error
+				EXT4FS_DBG("error in saving bitmap \%d", rc);
 			}
 
-			goto end;
-		}
-	}
-
-//	EXT4FS_DBG("try find free byte");
-
-	// Find free BYTE in bitmap
-	rc = ext4_bitmap_find_free_byte_and_set_bit(block->data, index_in_group, &rel_block_idx, block_size);
-	if (rc == EOK) {
-		block->dirty = true;
-		rc = block_put(block);
-		if (rc != EOK) {
-			// TODO error
-			EXT4FS_DBG("error in saving bitmap \%d", rc);
-		}
-
-		if (first_block == 0) {
-			allocated_block = blocks_per_group * block_group + rel_block_idx;
-		} else {
-			allocated_block = blocks_per_group * block_group + rel_block_idx + 1;
-		}
-
-		goto end;
-	}
-
-//	EXT4FS_DBG("try find free bit");
-
-	// Find free bit in bitmap
-	rc = ext4_bitmap_find_free_bit_and_set(block->data, index_in_group, &rel_block_idx, block_size);
-	if (rc == EOK) {
-		block->dirty = true;
-		rc = block_put(block);
-		if (rc != EOK) {
-			// TODO error
-			EXT4FS_DBG("error in saving bitmap \%d", rc);
-		}
-
-		if (first_block == 0) {
-			allocated_block = blocks_per_group * block_group + rel_block_idx;
-		} else {
-			allocated_block = blocks_per_group * block_group + rel_block_idx + 1;
-		}
-
-		goto end;
-	}
-
-
-	// TODO Try other block groups
-	EXT4FS_DBG("try other block group");
+			allocated_block = ext4_balloc_index_in_group2blockaddr(
+					fs->superblock, rel_block_idx, bgid);
+
+			EXT4FS_DBG("bit: block \%u allocated, index = \%u, goal = \%u", allocated_block, rel_block_idx, goal);
+
+			goto success;
+		}
+
+
+		// Next group
+		block_put(block);
+		ext4_filesystem_put_block_group_ref(bg_ref);
+		bgid = (bgid + 1) % block_group_count;
+		count--;
+	}
+
+	EXT4FS_DBG("No free block found");
 	return ENOSPC;
 
-end:
+success:
 
 	;
 //	EXT4FS_DBG("returning block \%u", allocated_block);
+
+	uint32_t block_size = ext4_superblock_get_block_size(fs->superblock);
 
 	// TODO decrement superblock free blocks count
@@ -329,18 +486,10 @@
 	ext4_filesystem_put_block_group_ref(bg_ref);
 
-//	EXT4FS_DBG("block \%u allocated", blocks_per_group * block_group + rel_block_idx + 1);
-
-
+//	if (goal > 1980)
+//		EXT4FS_DBG("block \%u allocated", allocated_block);
 
 	*fblock = allocated_block;
 	return EOK;
 }
-
-
-/**
- * @file	libext4_balloc.c
- * @brief	TODO
- */
-
 
 
Index: uspace/lib/ext4/libext4_balloc.h
===================================================================
--- uspace/lib/ext4/libext4_balloc.h	(revision e18de3c4ff73329ab91e81d578f312420d58e025)
+++ uspace/lib/ext4/libext4_balloc.h	(revision b12ca161211cc9652a5fedaf484bf00025c12c06)
@@ -37,7 +37,7 @@
 #include "libext4_filesystem.h"
 
-extern int ext4_bitmap_free_block(ext4_filesystem_t *,
+extern int ext4_balloc_free_block(ext4_filesystem_t *,
 		ext4_inode_ref_t *, uint32_t);
-extern int ext4_bitmap_alloc_block(ext4_filesystem_t *,
+extern int ext4_balloc_alloc_block(ext4_filesystem_t *,
 		ext4_inode_ref_t *, uint32_t *);
 
Index: uspace/lib/ext4/libext4_bitmap.c
===================================================================
--- uspace/lib/ext4/libext4_bitmap.c	(revision e18de3c4ff73329ab91e81d578f312420d58e025)
+++ uspace/lib/ext4/libext4_bitmap.c	(revision b12ca161211cc9652a5fedaf484bf00025c12c06)
@@ -76,30 +76,57 @@
 }
 
-int ext4_bitmap_find_free_byte_and_set_bit(uint8_t *bitmap, uint32_t start, uint32_t *index, uint32_t size)
+int ext4_bitmap_find_free_byte_and_set_bit(uint8_t *bitmap, uint32_t start, uint32_t *index, uint32_t max)
 {
-	uint8_t *pos = bitmap + (start / 8) + 1;
+	uint32_t idx;
+	if (start % 8) {
+		idx = start + (8 - (start % 8));
+	} else {
+		idx = start;
+	}
 
-	while (pos < bitmap + size) {
+	uint8_t *pos = bitmap + (idx / 8);
+
+	while (idx < max) {
+
 		if (*pos == 0) {
 			*pos |= 1;
 
-			*index = (pos - bitmap) * 8;
+			*index = idx;
 			return EOK;
 		}
 
+		idx += 8;
 		++pos;
 	}
 
 	return ENOSPC;
-
 }
 
-int ext4_bitmap_find_free_bit_and_set(uint8_t *bitmap, uint32_t start, uint32_t *index, uint32_t size)
+int ext4_bitmap_find_free_bit_and_set(uint8_t *bitmap, uint32_t start_idx,
+		uint32_t *index, uint32_t max)
 {
-	uint8_t *pos = bitmap + (start / 8);
-	int i;
-	uint8_t value, new_value;
+	uint8_t *pos = bitmap + (start_idx / 8);
+	uint32_t idx = start_idx;
+	bool byte_part = false;
 
-	while (pos < bitmap + size) {
+	// Check the rest of byte
+	while ((idx % 8) != 0) {
+		byte_part = true;
+
+		if (*pos & (1 << (idx % 8))) {
+			*pos |= (1 << (idx % 8));
+			*index = idx;
+			return EOK;
+		}
+
+		++idx;
+	}
+
+	if (byte_part) {
+		++pos;
+	}
+
+	while (idx < max) {
+
 		if ((*pos & 255) != 255) {
 			// free bit found
@@ -107,33 +134,18 @@
 		}
 
+		idx += 8;
 		++pos;
 	}
 
-	// Check the byte containing start
-	if (pos == bitmap + (start / 8)) {
-		for (i = start % 8; i < 8; ++i) {
-			value = *pos;
-			if ((value & (1 << i)) == 0) {
+
+	if (idx < max) {
+		for (uint8_t i = 0; i < 8; ++i) {
+			if ((*pos & (1 << i)) == 0) {
 				// free bit found
-				new_value = value | (1 << i);
-				*pos = new_value;
-				*index = (pos - bitmap) * 8 + i;
+				*pos |=  (1 << i);
+				*index = idx;
 				return EOK;
 			}
-		}
-	}
-
-	if (pos < bitmap + size) {
-
-		for(i = 0; i < 8; ++i) {
-			value = *pos;
-
-			if ((value & (1 << i)) == 0) {
-				// free bit found
-				new_value = value | (1 << i);
-				*pos = new_value;
-				*index = (pos - bitmap) * 8 + i;
-				return EOK;
-			}
+			idx++;
 		}
 	}
Index: uspace/lib/ext4/libext4_filesystem.c
===================================================================
--- uspace/lib/ext4/libext4_filesystem.c	(revision e18de3c4ff73329ab91e81d578f312420d58e025)
+++ uspace/lib/ext4/libext4_filesystem.c	(revision b12ca161211cc9652a5fedaf484bf00025c12c06)
@@ -72,6 +72,5 @@
 
 	/* Initialize block caching */
-	// TODO set cache MODE to write through (now writeback for faster testing)
-	rc = block_cache_init(service_id, block_size, 0, CACHE_MODE_WB);
+	rc = block_cache_init(service_id, block_size, 0, CACHE_MODE_WT);
 	if (rc != EOK) {
 		block_fini(fs->device);
@@ -387,5 +386,4 @@
 		// TODO
 		return ENOTSUP;
-
 	}
 
@@ -418,5 +416,5 @@
 
 	if (current_block == 0) {
-		rc = ext4_bitmap_alloc_block(fs, inode_ref, &new_block_addr);
+		rc = ext4_balloc_alloc_block(fs, inode_ref, &new_block_addr);
 		if (rc != EOK) {
 			// TODO error
@@ -460,32 +458,35 @@
 		current_block = uint32_t_le2host(((uint32_t*)block->data)[offset_in_block]);
 
-		if (current_block == 0) {
-			if (level > 1) {
-
-				rc = ext4_bitmap_alloc_block(fs, inode_ref, &new_block_addr);
-				if (rc != EOK) {
-					// TODO error
-					EXT4FS_DBG("allocation error");
-				}
-
-				rc = block_get(&new_block, fs->device, new_block_addr, BLOCK_FLAGS_NOREAD);
-				if (rc != EOK) {
-					// TODO error
-
-					EXT4FS_DBG("BBB: error block loading");
-
-				}
-				memset(new_block->data, 0, block_size);
-				new_block->dirty = true;
-
-				block_put(new_block);
-
-				((uint32_t*)block->data)[offset_in_block] = host2uint32_t_le(new_block_addr);
-				block->dirty = true;
-				current_block = new_block_addr;
-			} else {
-				((uint32_t*)block->data)[offset_in_block] = host2uint32_t_le(fblock);
-				block->dirty = true;
+		if ((level > 1) && (current_block == 0)) {
+			rc = ext4_balloc_alloc_block(fs, inode_ref, &new_block_addr);
+			if (rc != EOK) {
+				// TODO error
+				EXT4FS_DBG("allocation error");
 			}
+			EXT4FS_DBG("BBB: new addr \%u, offset = \%u, level = \%u", new_block_addr, offset_in_block, level);
+
+			rc = block_get(&new_block, fs->device, new_block_addr, BLOCK_FLAGS_NOREAD);
+			if (rc != EOK) {
+				// TODO error
+
+				EXT4FS_DBG("BBB: error block loading");
+
+			}
+			memset(new_block->data, 0, block_size);
+			new_block->dirty = true;
+
+			rc = block_put(new_block);
+			if (rc != EOK) {
+				EXT4FS_DBG("BBB: error indirect block saving");
+			}
+
+			((uint32_t*)block->data)[offset_in_block] = host2uint32_t_le(new_block_addr);
+			block->dirty = true;
+			current_block = new_block_addr;
+		}
+
+		if (level == 1) {
+			((uint32_t*)block->data)[offset_in_block] = host2uint32_t_le(fblock);
+			block->dirty = true;
 		}
 
@@ -537,5 +538,5 @@
 
 		ext4_inode_set_direct_block(inode, iblock, 0);
-		return ext4_bitmap_free_block(fs, inode_ref, fblock);
+		return ext4_balloc_free_block(fs, inode_ref, fblock);
 	}
 
@@ -601,8 +602,7 @@
 	}
 
-	return ext4_bitmap_free_block(fs, inode_ref, fblock);
-
-}
-
+	return ext4_balloc_free_block(fs, inode_ref, fblock);
+
+}
 
 /**
Index: uspace/lib/ext4/libext4_superblock.c
===================================================================
--- uspace/lib/ext4/libext4_superblock.c	(revision e18de3c4ff73329ab91e81d578f312420d58e025)
+++ uspace/lib/ext4/libext4_superblock.c	(revision b12ca161211cc9652a5fedaf484bf00025c12c06)
@@ -280,4 +280,47 @@
 }
 
+uint32_t ext4_superblock_get_block_group_count(ext4_superblock_t *sb)
+{
+	uint64_t blocks_count = ext4_superblock_get_blocks_count(sb);
+	uint32_t blocks_per_group = ext4_superblock_get_blocks_per_group(sb);
+
+	uint32_t block_groups_count = blocks_count / blocks_per_group;
+
+	if (blocks_count % blocks_per_group) {
+		block_groups_count++;
+	}
+
+	return block_groups_count;
+
+}
+
+uint32_t ext4_superblock_get_blocks_in_group(ext4_superblock_t *sb, uint32_t bgid)
+{
+	uint32_t block_group_count = ext4_superblock_get_block_group_count(sb);
+	uint32_t blocks_per_group = ext4_superblock_get_blocks_per_group(sb);
+	uint64_t total_blocks = ext4_superblock_get_blocks_count(sb);
+
+	if (bgid < block_group_count - 1) {
+		return blocks_per_group;
+	} else {
+		return (total_blocks - ((block_group_count - 1) * blocks_per_group));
+	}
+
+}
+
+uint32_t ext4_superblock_get_inodes_in_group(ext4_superblock_t *sb, uint32_t bgid)
+{
+	uint32_t block_group_count = ext4_superblock_get_block_group_count(sb);
+	uint32_t inodes_per_group = ext4_superblock_get_inodes_per_group(sb);
+	uint32_t total_inodes = ext4_superblock_get_inodes_count(sb);
+
+	if (bgid < block_group_count - 1) {
+		return inodes_per_group;
+	} else {
+		return (total_inodes - ((block_group_count - 1) * inodes_per_group));
+	}
+
+}
+
 /**
  * @}
Index: uspace/lib/ext4/libext4_superblock.h
===================================================================
--- uspace/lib/ext4/libext4_superblock.h	(revision e18de3c4ff73329ab91e81d578f312420d58e025)
+++ uspace/lib/ext4/libext4_superblock.h	(revision b12ca161211cc9652a5fedaf484bf00025c12c06)
@@ -302,4 +302,8 @@
 extern int ext4_superblock_check_sanity(ext4_superblock_t *);
 
+extern uint32_t ext4_superblock_get_block_group_count(ext4_superblock_t *);
+extern uint32_t ext4_superblock_get_blocks_in_group(ext4_superblock_t *, uint32_t);
+extern uint32_t ext4_superblock_get_inodes_in_group(ext4_superblock_t *, uint32_t);
+
 #endif
 
Index: uspace/srv/fs/ext4fs/ext4fs_ops.c
===================================================================
--- uspace/srv/fs/ext4fs/ext4fs_ops.c	(revision e18de3c4ff73329ab91e81d578f312420d58e025)
+++ uspace/srv/fs/ext4fs/ext4fs_ops.c	(revision b12ca161211cc9652a5fedaf484bf00025c12c06)
@@ -973,5 +973,5 @@
 	if (fblock == 0) {
 
-		rc =  ext4_bitmap_alloc_block(fs, inode_ref, &fblock);
+		rc =  ext4_balloc_alloc_block(fs, inode_ref, &fblock);
 		if (rc != EOK) {
 			EXT4FS_DBG("allocation failed");
@@ -981,9 +981,11 @@
 		}
 
-		ext4_filesystem_set_inode_data_block_index(fs, inode_ref, iblock, fblock);
+		rc = ext4_filesystem_set_inode_data_block_index(fs, inode_ref, iblock, fblock);
+		if (rc != EOK) {
+			EXT4FS_DBG("ERROR: setting index failed");
+		}
 		inode_ref->dirty = true;
 
 		flags = BLOCK_FLAGS_NOREAD;
-
 	}
 
