Index: uspace/lib/ext4/libext4_balloc.c
===================================================================
--- uspace/lib/ext4/libext4_balloc.c	(revision 7f295759166093a44a7ee1aceee7f7af5443f538)
+++ uspace/lib/ext4/libext4_balloc.c	(revision d76973c2bfdc27bfc941ad522218564772836ded)
@@ -135,17 +135,10 @@
 }
 
-/** Free continuous set of blocks.
- *
- * @param inode_ref Inode, where the blocks are allocated
- * @param first     First block to release
- * @param count     Number of blocks to release
- *
- */
-int ext4_balloc_free_blocks(ext4_inode_ref_t *inode_ref,
+static int ext4_balloc_free_blocks_internal(ext4_inode_ref_t *inode_ref,
     uint32_t first, uint32_t count)
 {
 	ext4_filesystem_t *fs = inode_ref->fs;
 	ext4_superblock_t *sb = fs->superblock;
-	
+
 	/* Compute indexes */
 	uint32_t block_group_first =
@@ -153,7 +146,7 @@
 	uint32_t block_group_last =
 	    ext4_balloc_get_bgid_of_block(sb, first + count - 1);
-	
+
 	assert(block_group_first == block_group_last);
-	
+
 	/* Load block group reference */
 	ext4_block_group_ref_t *bg_ref;
@@ -161,12 +154,12 @@
 	if (rc != EOK)
 		return rc;
-	
+
 	uint32_t index_in_group_first =
 	    ext4_filesystem_blockaddr2_index_in_group(sb, first);
-	
+
 	/* Load block with bitmap */
 	uint32_t bitmap_block_addr =
 	    ext4_block_group_get_block_bitmap(bg_ref->block_group, sb);
-	
+
 	block_t *bitmap_block;
 	rc = block_get(&bitmap_block, fs->device, bitmap_block_addr, 0);
@@ -175,9 +168,9 @@
 		return rc;
 	}
-	
+
 	/* Modify bitmap */
 	ext4_bitmap_free_bits(bitmap_block->data, index_in_group_first, count);
 	bitmap_block->dirty = true;
-	
+
 	/* Release block with bitmap */
 	rc = block_put(bitmap_block);
@@ -187,7 +180,7 @@
 		return rc;
 	}
-	
+
 	uint32_t block_size = ext4_superblock_get_block_size(sb);
-	
+
 	/* Update superblock free blocks count */
 	uint32_t sb_free_blocks =
@@ -195,5 +188,5 @@
 	sb_free_blocks += count;
 	ext4_superblock_set_free_blocks_count(sb, sb_free_blocks);
-	
+
 	/* Update inode blocks count */
 	uint64_t ino_blocks =
@@ -202,5 +195,5 @@
 	ext4_inode_set_blocks_count(sb, inode_ref->inode, ino_blocks);
 	inode_ref->dirty = true;
-	
+
 	/* Update block group free blocks count */
 	uint32_t free_blocks =
@@ -210,9 +203,52 @@
 	    sb, free_blocks);
 	bg_ref->dirty = true;
-	
+
 	/* Release block group reference */
 	return ext4_filesystem_put_block_group_ref(bg_ref);
 }
 
+/** Free continuous set of blocks.
+ *
+ * @param inode_ref Inode, where the blocks are allocated
+ * @param first     First block to release
+ * @param count     Number of blocks to release
+ *
+ */
+int ext4_balloc_free_blocks(ext4_inode_ref_t *inode_ref,
+    uint32_t first, uint32_t count)
+{
+	int r;
+	uint32_t gid;
+	uint64_t limit;
+	ext4_filesystem_t *fs = inode_ref->fs;
+	ext4_superblock_t *sb = fs->superblock;
+
+	while (count) {
+		gid = ext4_filesystem_blockaddr2group(sb, first);
+		limit = ext4_filesystem_index_in_group2blockaddr(sb, 0,
+		    gid + 1);
+
+		if ((first + count) >= limit) {
+			/* This extent spans over 2 or more block groups,
+			 * we'll break it into smaller parts.
+			 */
+			uint32_t s = limit - first;
+
+			r = ext4_balloc_free_blocks_internal(inode_ref,
+			    first, s);
+			if (r != EOK)
+				return r;
+
+			first = limit;
+			count -= s;
+		} else {
+			return ext4_balloc_free_blocks_internal(inode_ref,
+			    first, count);
+		}
+	}
+
+	return EOK;
+}
+
 /** Compute first block for data in block group.
  *
@@ -227,28 +263,49 @@
     ext4_block_group_ref_t *bg_ref)
 {
-	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_ref->block_group, sb);
-	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 (bg_ref->index < 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;
+	uint32_t r;
+	uint64_t itable = ext4_block_group_get_inode_table_first_block(
+	    bg_ref->block_group, sb);
+	uint32_t itable_sz = ext4_filesystem_bg_get_itable_size(sb, bg_ref);
+
+	if (!ext4_superblock_has_feature_incompatible(sb,
+	    EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
+		/* If we are not using FLEX_BG, the first data block
+		 * is always after the inode table.
+		 */
+		r = itable + itable_sz;
+		return ext4_filesystem_blockaddr2_index_in_group(sb, r);
+	}
+
+	uint64_t bbmap = ext4_block_group_get_block_bitmap(bg_ref->block_group,
+	    sb);
+	uint64_t ibmap = ext4_block_group_get_inode_bitmap(bg_ref->block_group,
+	    sb);
+
+	r = ext4_filesystem_bg_get_backup_blocks(bg_ref);
+
+	if (ext4_filesystem_blockaddr2group(sb, bbmap) == bg_ref->index)
+		bbmap = ext4_filesystem_blockaddr2_index_in_group(sb, bbmap);
+	else
+		bbmap = -1; /* Invalid */
+
+	if (ext4_filesystem_blockaddr2group(sb, ibmap) == bg_ref->index)
+		ibmap = ext4_filesystem_blockaddr2_index_in_group(sb, ibmap);
+	else
+		ibmap = -1;
+
+	while (1) {
+		uint64_t r_abs = ext4_filesystem_index_in_group2blockaddr(sb,
+			r, bg_ref->index);
+
+		if (r == bbmap || r == ibmap)
+			r++;
+		else if (r_abs >= itable && r_abs < itable_sz) {
+			r = ext4_filesystem_blockaddr2_index_in_group(sb,
+			    itable + itable_sz);
+		} else
+			break;
+	}
+
+	return r;
 }
 
Index: uspace/lib/ext4/libext4_filesystem.c
===================================================================
--- uspace/lib/ext4/libext4_filesystem.c	(revision 7f295759166093a44a7ee1aceee7f7af5443f538)
+++ uspace/lib/ext4/libext4_filesystem.c	(revision d76973c2bfdc27bfc941ad522218564772836ded)
@@ -251,4 +251,18 @@
 }
 
+/** Convert the absolute block number to group number
+ *
+ * @param sb    Pointer to the superblock
+ * @param b     Absolute block number
+ *
+ * @return      Group number
+ */
+uint32_t ext4_filesystem_blockaddr2group(ext4_superblock_t *sb, uint64_t b)
+{
+	uint32_t blocks_per_group = ext4_superblock_get_blocks_per_group(sb);
+
+	return b / blocks_per_group;
+}
+
 /** Initialize block bitmap in block group.
  *
@@ -260,6 +274,13 @@
 static int ext4_filesystem_init_block_bitmap(ext4_block_group_ref_t *bg_ref)
 {
+	uint64_t itb;
+	uint32_t sz;
+	uint32_t i;
+
 	/* Load bitmap */
-	uint32_t bitmap_block_addr = ext4_block_group_get_block_bitmap(
+	ext4_superblock_t *sb = bg_ref->fs->superblock;
+	uint64_t bitmap_block_addr = ext4_block_group_get_block_bitmap(
+	    bg_ref->block_group, bg_ref->fs->superblock);
+	uint64_t bitmap_inode_addr = ext4_block_group_get_inode_bitmap(
 	    bg_ref->block_group, bg_ref->fs->superblock);
 	
@@ -273,19 +294,40 @@
 	
 	/* Initialize all bitmap bits to zero */
-	uint32_t block_size = ext4_superblock_get_block_size(bg_ref->fs->superblock);
+	uint32_t block_size = ext4_superblock_get_block_size(sb);
 	memset(bitmap, 0, block_size);
 	
-	/* Determine first block and first data block in group */
-	uint32_t first_idx = 0;
-	
-	uint32_t first_data = ext4_balloc_get_first_data_block_in_group(
-	    bg_ref->fs->superblock, bg_ref);
-	uint32_t first_data_idx = ext4_filesystem_blockaddr2_index_in_group(
-	    bg_ref->fs->superblock, first_data);
-	
+	/* Determine the number of reserved blocks in the group */
+	uint32_t reserved_cnt = ext4_filesystem_bg_get_backup_blocks(bg_ref);
+
 	/* Set bits from to first block to first data block - 1 to one (allocated) */
-	for (uint32_t block = first_idx; block < first_data_idx; ++block)
+	for (uint32_t block = 0; block < reserved_cnt; ++block)
 		ext4_bitmap_set_bit(bitmap, block);
-	
+
+	uint32_t bitmap_block_gid = ext4_filesystem_blockaddr2group(sb,
+	    bitmap_block_addr);
+	if (bitmap_block_gid == bg_ref->index) {
+		ext4_bitmap_set_bit(bitmap,
+		    ext4_filesystem_blockaddr2_index_in_group(sb, bitmap_block_addr));
+	}
+
+	uint32_t bitmap_inode_gid = ext4_filesystem_blockaddr2group(sb,
+	    bitmap_inode_addr);
+	if (bitmap_inode_gid == bg_ref->index) {
+		ext4_bitmap_set_bit(bitmap,
+		    ext4_filesystem_blockaddr2_index_in_group(sb, bitmap_inode_addr));
+	}
+
+	itb = ext4_block_group_get_inode_table_first_block(bg_ref->block_group,
+	    sb);
+	sz = ext4_filesystem_bg_get_itable_size(sb, bg_ref);
+
+	for (i = 0; i < sz; ++i, ++itb) {
+		uint32_t gid = ext4_filesystem_blockaddr2group(sb, itb);
+		if (gid == bg_ref->index) {
+			ext4_bitmap_set_bit(bitmap,
+			    ext4_filesystem_blockaddr2_index_in_group(sb, itb));
+		}
+	}
+
 	bitmap_block->dirty = true;
 	
@@ -524,4 +566,33 @@
 }
 
+/** Get the size of the block group's inode table
+ *
+ * @param sb     Pointer to the superblock
+ * @param bg_ref Pointer to the block group reference
+ *
+ * @return       Size of the inode table in blocks.
+ */
+uint32_t ext4_filesystem_bg_get_itable_size(ext4_superblock_t *sb,
+    ext4_block_group_ref_t *bg_ref)
+{
+	uint32_t itable_size;
+	uint32_t block_group_count = ext4_superblock_get_block_group_count(sb);
+	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);
+
+	if (bg_ref->index < block_group_count - 1) {
+		itable_size = 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);
+		itable_size =
+		    (inodes_count_total - ((block_group_count - 1) * inodes_per_group)) *
+		    inode_table_item_size;
+	}
+
+	return ROUND_UP(itable_size, block_size) / block_size;
+}
+
 /* Check if n is a power of p */
 static bool is_power_of(uint32_t n, unsigned p)
@@ -548,5 +619,5 @@
  * @return      Number of blocks
  */
-uint32_t ext4_block_group_get_backup_blocks(ext4_block_group_ref_t *bg)
+uint32_t ext4_filesystem_bg_get_backup_blocks(ext4_block_group_ref_t *bg)
 {
 	uint32_t const idx = bg->index;
Index: uspace/lib/ext4/libext4_filesystem.h
===================================================================
--- uspace/lib/ext4/libext4_filesystem.h	(revision 7f295759166093a44a7ee1aceee7f7af5443f538)
+++ uspace/lib/ext4/libext4_filesystem.h	(revision d76973c2bfdc27bfc941ad522218564772836ded)
@@ -47,4 +47,5 @@
 extern uint32_t ext4_filesystem_index_in_group2blockaddr(ext4_superblock_t *,
     uint32_t, uint32_t);
+extern uint32_t ext4_filesystem_blockaddr2group(ext4_superblock_t *, uint64_t);
 extern int ext4_filesystem_get_block_group_ref(ext4_filesystem_t *, uint32_t,
     ext4_block_group_ref_t **);
@@ -64,5 +65,7 @@
 extern int ext4_filesystem_append_inode_block(ext4_inode_ref_t *, uint32_t *,
     uint32_t *);
-uint32_t ext4_block_group_get_backup_blocks(ext4_block_group_ref_t *bg);
+uint32_t ext4_filesystem_bg_get_backup_blocks(ext4_block_group_ref_t *bg);
+uint32_t ext4_filesystem_bg_get_itable_size(ext4_superblock_t *sb,
+    ext4_block_group_ref_t *bg_ref);
 
 #endif
Index: uspace/lib/ext4/libext4_types.h
===================================================================
--- uspace/lib/ext4/libext4_types.h	(revision 7f295759166093a44a7ee1aceee7f7af5443f538)
+++ uspace/lib/ext4/libext4_types.h	(revision d76973c2bfdc27bfc941ad522218564772836ded)
@@ -214,5 +214,6 @@
 	(EXT4_FEATURE_INCOMPAT_FILETYPE | \
 	EXT4_FEATURE_INCOMPAT_EXTENTS | \
-	EXT4_FEATURE_INCOMPAT_64BIT)
+	EXT4_FEATURE_INCOMPAT_64BIT | \
+	EXT4_FEATURE_INCOMPAT_FLEX_BG)
 
 #define EXT4_FEATURE_RO_COMPAT_SUPP \
