Index: uspace/lib/ext4/libext4_bitmap.c
===================================================================
--- uspace/lib/ext4/libext4_bitmap.c	(revision 35f48f2356b9a59df7e8e43a80a9bc8b567441b8)
+++ uspace/lib/ext4/libext4_bitmap.c	(revision 1e65444c9acc63f6529592d1ff555f2ed53bff70)
@@ -43,6 +43,9 @@
 static void ext4_bitmap_free_bit(uint8_t *bitmap, uint32_t index)
 {
+	// Block numbers are 1-based
 	uint32_t byte_index = index / 8;
 	uint32_t bit_index = index % 8;
+
+//	EXT4FS_DBG("freeing block \%u, byte \%u and bit \%u", index, byte_index, bit_index);
 
 	uint8_t *target = bitmap + byte_index;
@@ -59,4 +62,5 @@
 	int i;
 	uint32_t idx = 0;
+	uint8_t value, new_value;
 
 	while (pos < bitmap + size) {
@@ -72,13 +76,17 @@
 	if (pos < bitmap + size) {
 
+//		EXT4FS_DBG("byte found \%u", (uint32_t)(pos - bitmap));
+
 		for(i = 0; i < 8; ++i) {
-			if ((*pos & (1 << i)) == 0) {
+			value = *pos;
+
+			if ((value & (1 << i)) == 0) {
 				// free bit found
-				*pos |= (1 << i);
-				*index = idx;
+//				EXT4FS_DBG("bit found \%u", i);
+				new_value = value | (1 << i);
+				*pos = new_value;
+				*index = idx + i;
 				return EOK;
 			}
-
-			idx++;
 		}
 	}
@@ -98,6 +106,6 @@
 
 	blocks_per_group = ext4_superblock_get_blocks_per_group(fs->superblock);
-	block_group = block_index / blocks_per_group;
-	index_in_group = block_index % blocks_per_group;
+	block_group = ((block_index - 1) / blocks_per_group);
+	index_in_group = (block_index - 1) % blocks_per_group;
 
 	rc = ext4_filesystem_get_block_group_ref(fs, block_group, &bg_ref);
@@ -133,4 +141,6 @@
 		return rc;
 	}
+
+	EXT4FS_DBG("block \%u released", block_index);
 
 	return EOK;
@@ -148,5 +158,5 @@
 
 	inodes_per_group = ext4_superblock_get_inodes_per_group(fs->superblock);
-	block_group = inode_ref->index / inodes_per_group;
+	block_group = (inode_ref->index - 1) / inodes_per_group;
 
 	block_size = ext4_superblock_get_block_size(fs->superblock);
@@ -166,10 +176,13 @@
 
 	rc = ext4_bitmap_find_free_bit_and_set(block->data, &rel_block_idx, block_size);
-
-
 	if (rc != EOK) {
 		EXT4FS_DBG("no block found");
 		// TODO if ENOSPC - try next block group - try next block groups
 	}
+
+	block->dirty = true;
+
+	// TODO check retval
+	block_put(block);
 
 	// TODO decrement superblock free blocks count
@@ -179,11 +192,15 @@
 
 	uint32_t bg_free_blocks = ext4_block_group_get_free_blocks_count(bg_ref->block_group);
-	bg_free_blocks++;
+	bg_free_blocks--;
 	ext4_block_group_set_free_blocks_count(bg_ref->block_group, bg_free_blocks);
 	bg_ref->dirty = true;
 
-	// return
+	ext4_filesystem_put_block_group_ref(bg_ref);
+
 	blocks_per_group = ext4_superblock_get_blocks_per_group(fs->superblock);
-	*fblock = blocks_per_group * block_group + rel_block_idx;
+
+	EXT4FS_DBG("block \%u allocated", blocks_per_group * block_group + rel_block_idx + 1);
+
+	*fblock = blocks_per_group * block_group + rel_block_idx + 1;
 	return EOK;
 
Index: uspace/lib/ext4/libext4_filesystem.c
===================================================================
--- uspace/lib/ext4/libext4_filesystem.c	(revision 35f48f2356b9a59df7e8e43a80a9bc8b567441b8)
+++ uspace/lib/ext4/libext4_filesystem.c	(revision 1e65444c9acc63f6529592d1ff555f2ed53bff70)
@@ -364,18 +364,19 @@
 
 int ext4_filesystem_set_inode_data_block_index(ext4_filesystem_t *fs,
-		ext4_inode_t *inode, aoff64_t iblock, uint32_t fblock)
-{
-
-//	int rc;
-//	uint32_t offset_in_block;
-//	uint32_t current_block;
-//	aoff64_t block_offset_in_level;
-//	int i;
-//	int level;
-//	block_t *block;
+		ext4_inode_ref_t *inode_ref, aoff64_t iblock, uint32_t fblock)
+{
+
+	int rc;
+	uint32_t offset_in_block;
+	uint32_t current_block, new_block_addr;
+	uint32_t block_size;
+	aoff64_t block_offset_in_level;
+	int i;
+	int level;
+	block_t *block, *new_block;
 
 	/* Handle inode using extents */
 	if (ext4_superblock_has_feature_compatible(fs->superblock, EXT4_FEATURE_INCOMPAT_EXTENTS) &&
-			ext4_inode_has_flag(inode, EXT4_INODE_FLAG_EXTENTS)) {
+			ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS)) {
 		// TODO
 		return ENOTSUP;
@@ -385,67 +386,113 @@
 	/* Handle simple case when we are dealing with direct reference */
 	if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
-		ext4_inode_set_direct_block(inode, (uint32_t)iblock, fblock);
+		ext4_inode_set_direct_block(inode_ref->inode, (uint32_t)iblock, fblock);
+		inode_ref->dirty = true;
 		return EOK;
 	}
 
-//	/* Determine the indirection level needed to get the desired block */
-//	level = -1;
-//	for (i = 1; i < 4; i++) {
-//		if (iblock < fs->inode_block_limits[i]) {
-//			level = i;
-//			break;
-//		}
-//	}
-//
-//	if (level == -1) {
-//		return EIO;
-//	}
-//
-//	/* Compute offsets for the topmost level */
-//	block_offset_in_level = iblock - fs->inode_block_limits[level-1];
-//	current_block = ext4_inode_get_indirect_block(inode, level-1);
-//	offset_in_block = block_offset_in_level / fs->inode_blocks_per_level[level-1];
-//
-//	/* Navigate through other levels, until we find the block number
-//	 * or find null reference meaning we are dealing with sparse file
-//	 */
-//	while (level > 0) {
-//		rc = block_get(&block, fs->device, current_block, 0);
-//		if (rc != EOK) {
-//			return rc;
-//		}
-//
-//		current_block = uint32_t_le2host(((uint32_t*)block->data)[offset_in_block]);
-//
-//		rc = block_put(block);
-//		if (rc != EOK) {
-//			return rc;
-//		}
-//
-//		if (current_block == 0) {
-//			/* This is a sparse file */
-//			*fblock = 0;
-//			return EOK;
-//		}
-//
-//		level -= 1;
-//
-//		/* If we are on the last level, break here as
-//		 * there is no next level to visit
-//		 */
-//		if (level == 0) {
-//			break;
-//		}
-//
-//		/* Visit the next level */
-//		block_offset_in_level %= fs->inode_blocks_per_level[level];
-//		offset_in_block = block_offset_in_level / fs->inode_blocks_per_level[level-1];
-//	}
-//
-//	*fblock = current_block;
-//
-//	return EOK;
-//
-//
+	/* Determine the indirection level needed to get the desired block */
+	level = -1;
+	for (i = 1; i < 4; i++) {
+		if (iblock < fs->inode_block_limits[i]) {
+			level = i;
+			break;
+		}
+	}
+
+	if (level == -1) {
+		return EIO;
+	}
+
+	block_size = ext4_superblock_get_block_size(fs->superblock);
+
+	/* Compute offsets for the topmost level */
+	block_offset_in_level = iblock - fs->inode_block_limits[level-1];
+	current_block = ext4_inode_get_indirect_block(inode_ref->inode, level-1);
+	offset_in_block = block_offset_in_level / fs->inode_blocks_per_level[level-1];
+
+	if (current_block == 0) {
+		rc = ext4_bitmap_alloc_block(fs, inode_ref, &new_block_addr);
+		if (rc != EOK) {
+			// TODO error
+		}
+		EXT4FS_DBG("AAA: new addr \%u, level = \%u", new_block_addr, level);
+
+		ext4_inode_set_indirect_block(inode_ref->inode, level - 1, new_block_addr);
+
+		inode_ref->dirty = true;
+
+		rc = block_get(&new_block, fs->device, new_block_addr, BLOCK_FLAGS_NOREAD);
+		if (rc != EOK) {
+			EXT4FS_DBG("block load error");
+			// TODO error
+		}
+
+		memset(new_block->data, 0, block_size);
+		new_block->dirty = true;
+
+		rc = block_put(new_block);
+		if (rc != EOK) {
+			EXT4FS_DBG("block put error");
+		}
+
+		current_block = new_block_addr;
+	}
+
+	/* Navigate through other levels, until we find the block number
+	 * or find null reference meaning we are dealing with sparse file
+	 */
+	while (level > 0) {
+
+		rc = block_get(&block, fs->device, current_block, 0);
+		if (rc != EOK) {
+			return rc;
+		}
+
+		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
+				}
+
+				rc = block_get(&new_block, fs->device, new_block_addr, BLOCK_FLAGS_NOREAD);
+				if (rc != EOK) {
+					// TODO error
+				}
+				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;
+			}
+		}
+
+		rc = block_put(block);
+		if (rc != EOK) {
+			return rc;
+		}
+
+		level -= 1;
+
+		/* If we are on the last level, break here as
+		 * there is no next level to visit
+		 */
+		if (level == 0) {
+			break;
+		}
+
+		/* Visit the next level */
+		block_offset_in_level %= fs->inode_blocks_per_level[level];
+		offset_in_block = block_offset_in_level / fs->inode_blocks_per_level[level-1];
+	}
 
 	return EOK;
Index: uspace/lib/ext4/libext4_filesystem.h
===================================================================
--- uspace/lib/ext4/libext4_filesystem.h	(revision 35f48f2356b9a59df7e8e43a80a9bc8b567441b8)
+++ uspace/lib/ext4/libext4_filesystem.h	(revision 1e65444c9acc63f6529592d1ff555f2ed53bff70)
@@ -63,5 +63,5 @@
 	ext4_inode_t *, aoff64_t iblock, uint32_t *);
 extern int ext4_filesystem_set_inode_data_block_index(ext4_filesystem_t *,
-		ext4_inode_t *, aoff64_t, uint32_t);
+		ext4_inode_ref_t *, aoff64_t, uint32_t);
 extern int ext4_filesystem_release_inode_block(ext4_filesystem_t *,
 		ext4_inode_ref_t *, uint32_t);
Index: uspace/lib/ext4/libext4_inode.c
===================================================================
--- uspace/lib/ext4/libext4_inode.c	(revision 35f48f2356b9a59df7e8e43a80a9bc8b567441b8)
+++ uspace/lib/ext4/libext4_inode.c	(revision 1e65444c9acc63f6529592d1ff555f2ed53bff70)
@@ -97,5 +97,5 @@
 }
 
-uint32_t ext4_inode_get_direct_block(ext4_inode_t *inode, uint8_t idx)
+uint32_t ext4_inode_get_direct_block(ext4_inode_t *inode, uint32_t idx)
 {
 	assert(idx < EXT4_INODE_DIRECT_BLOCK_COUNT);
@@ -103,5 +103,5 @@
 }
 
-void ext4_inode_set_direct_block(ext4_inode_t *inode, uint8_t idx, uint32_t fblock)
+void ext4_inode_set_direct_block(ext4_inode_t *inode, uint32_t idx, uint32_t fblock)
 {
 	assert(idx < EXT4_INODE_DIRECT_BLOCK_COUNT);
@@ -109,9 +109,14 @@
 }
 
-uint32_t ext4_inode_get_indirect_block(ext4_inode_t *inode, uint8_t idx)
-{
-	assert(idx < EXT4_INODE_INDIRECT_BLOCK_COUNT);
+uint32_t ext4_inode_get_indirect_block(ext4_inode_t *inode, uint32_t idx)
+{
 	return uint32_t_le2host(inode->blocks[idx + EXT4_INODE_INDIRECT_BLOCK]);
 }
+
+void ext4_inode_set_indirect_block(ext4_inode_t *inode, uint32_t idx, uint32_t fblock)
+{
+	inode->blocks[idx + EXT4_INODE_INDIRECT_BLOCK] = host2uint32_t_le(fblock);
+}
+
 
 uint32_t ext4_inode_get_extent_block(ext4_inode_t *inode, uint64_t idx, service_id_t service_id)
Index: uspace/lib/ext4/libext4_inode.h
===================================================================
--- uspace/lib/ext4/libext4_inode.h	(revision 35f48f2356b9a59df7e8e43a80a9bc8b567441b8)
+++ uspace/lib/ext4/libext4_inode.h	(revision 1e65444c9acc63f6529592d1ff555f2ed53bff70)
@@ -168,7 +168,8 @@
 extern uint32_t ext4_inode_get_flags(ext4_inode_t *);
 
-extern uint32_t ext4_inode_get_direct_block(ext4_inode_t *, uint8_t);
-extern void ext4_inode_set_direct_block(ext4_inode_t *, uint8_t, uint32_t);
-extern uint32_t ext4_inode_get_indirect_block(ext4_inode_t *, uint8_t);
+extern uint32_t ext4_inode_get_direct_block(ext4_inode_t *, uint32_t);
+extern void ext4_inode_set_direct_block(ext4_inode_t *, uint32_t, uint32_t);
+extern uint32_t ext4_inode_get_indirect_block(ext4_inode_t *, uint32_t);
+extern void ext4_inode_set_indirect_block(ext4_inode_t *, uint32_t, uint32_t);
 extern uint32_t ext4_inode_get_extent_block(ext4_inode_t *, uint64_t, service_id_t);
 /*
Index: uspace/srv/fs/ext4fs/ext4fs_ops.c
===================================================================
--- uspace/srv/fs/ext4fs/ext4fs_ops.c	(revision 35f48f2356b9a59df7e8e43a80a9bc8b567441b8)
+++ uspace/srv/fs/ext4fs/ext4fs_ops.c	(revision 1e65444c9acc63f6529592d1ff555f2ed53bff70)
@@ -926,6 +926,4 @@
     size_t *wbytes, aoff64_t *nsize)
 {
-	EXT4FS_DBG("");
-
 	int rc;
 	int flags = BLOCK_FLAGS_NONE;
@@ -966,5 +964,5 @@
 	}
 
-	EXT4FS_DBG("bytes == \%u", bytes);
+//	EXT4FS_DBG("bytes == \%u", bytes);
 
 	iblock =  pos / block_size;
@@ -973,5 +971,5 @@
 
 	if (fblock == 0) {
-		EXT4FS_DBG("Allocate block !!!");
+//		EXT4FS_DBG("Allocate block !!!");
 		rc =  ext4_bitmap_alloc_block(fs, inode_ref, &fblock);
 		if (rc != EOK) {
@@ -981,10 +979,10 @@
 		}
 
-		ext4_filesystem_set_inode_data_block_index(fs, inode_ref->inode, iblock, fblock);
+		ext4_filesystem_set_inode_data_block_index(fs, inode_ref, iblock, fblock);
 		inode_ref->dirty = true;
 
 		flags = BLOCK_FLAGS_NOREAD;
 
-		EXT4FS_DBG("block \%u allocated", fblock);
+//		EXT4FS_DBG("block \%u allocated", fblock);
 	}
 
@@ -996,8 +994,6 @@
 	}
 
-	EXT4FS_DBG("block loaded");
-
 	if (flags == BLOCK_FLAGS_NOREAD) {
-		EXT4FS_DBG("fill block with zeros");
+//		EXT4FS_DBG("fill block with zeros");
 		memset(write_block->data, 0, block_size);
 	}
@@ -1005,13 +1001,8 @@
 	rc = async_data_write_finalize(callid, write_block->data + (pos % block_size), bytes);
 	if (rc != EOK) {
+		// TODO error
 		EXT4FS_DBG("error in write finalize \%d", rc);
 	}
 
-	char *data = write_block->data + (pos % block_size);
-	for (uint32_t x = 0; x < bytes; ++x) {
-		printf("%c", data[x]);
-	}
-	printf("\n");
-
 	write_block->dirty = true;
 
@@ -1022,5 +1013,5 @@
 	}
 
-	EXT4FS_DBG("writing finished");
+//	EXT4FS_DBG("writing finished");
 
 	old_inode_size = ext4_inode_get_size(fs->superblock, inode_ref->inode);
