Index: uspace/app/mkext4/mkext4.c
===================================================================
--- uspace/app/mkext4/mkext4.c	(revision 09d1b6fa795d872855bb1d46fc118f64674b45be)
+++ uspace/app/mkext4/mkext4.c	(revision 3c8b0a8a677ff6f5ef9864930b02e6aa7dcb0cc6)
@@ -56,4 +56,5 @@
 	aoff64_t nblocks;
 	const char *label = "";
+	unsigned int bsize = 1024;
 
 	cfg.version = ext4_def_fs_version;
@@ -79,4 +80,25 @@
 
 			nblocks = strtol(*argv, &endptr, 10);
+			if (*endptr != '\0') {
+				printf(NAME ": Error, invalid argument.\n");
+				syntax_print();
+				return 1;
+			}
+
+			--argc;
+			++argv;
+			continue;
+		}
+
+		if (str_cmp(*argv, "--bsize") == 0) {
+			--argc;
+			++argv;
+			if (*argv == NULL) {
+				printf(NAME ": Error, argument missing.\n");
+				syntax_print();
+				return 1;
+			}
+
+			bsize = strtol(*argv, &endptr, 10);
 			if (*endptr != '\0') {
 				printf(NAME ": Error, invalid argument.\n");
@@ -159,4 +181,5 @@
 
 	cfg.volume_name = label;
+	cfg.bsize = bsize;
 	(void) nblocks;
 
@@ -178,5 +201,6 @@
 	    "\t--size <sectors> Filesystem size, overrides device size\n"
 	    "\t--label <label>  Volume label\n"
-	    "\t--type <fstype>  Filesystem type (ext2, ext2old)\n");
+	    "\t--type <fstype>  Filesystem type (ext2, ext2old)\n"
+	    "\t--bsize <bytes>  Filesystem block size in bytes (default = 1024)\n");
 }
 
Index: uspace/lib/ext4/include/ext4/cfg.h
===================================================================
--- uspace/lib/ext4/include/ext4/cfg.h	(revision 09d1b6fa795d872855bb1d46fc118f64674b45be)
+++ uspace/lib/ext4/include/ext4/cfg.h	(revision 3c8b0a8a677ff6f5ef9864930b02e6aa7dcb0cc6)
@@ -53,4 +53,6 @@
 	/** Volume name encoded as UTF-8 string */
 	const char *volume_name;
+	/** Filesystem block size */
+	size_t bsize;
 } ext4_cfg_t;
 
Index: uspace/lib/ext4/include/ext4/superblock.h
===================================================================
--- uspace/lib/ext4/include/ext4/superblock.h	(revision 09d1b6fa795d872855bb1d46fc118f64674b45be)
+++ uspace/lib/ext4/include/ext4/superblock.h	(revision 3c8b0a8a677ff6f5ef9864930b02e6aa7dcb0cc6)
@@ -147,4 +147,5 @@
 extern void ext4_superblock_set_reserved_gdt_blocks(ext4_superblock_t *sb,
     uint32_t n);
+extern uint32_t ext4_superblock_get_flex_group_size(ext4_superblock_t *sb);
 
 /* More complex superblock functions */
Index: uspace/lib/ext4/src/balloc.c
===================================================================
--- uspace/lib/ext4/src/balloc.c	(revision 09d1b6fa795d872855bb1d46fc118f64674b45be)
+++ uspace/lib/ext4/src/balloc.c	(revision 3c8b0a8a677ff6f5ef9864930b02e6aa7dcb0cc6)
@@ -261,32 +261,28 @@
 		 * is always after the inode table.
 		 */
+		return itable + itable_sz;
+	}
+
+	uint32_t flex_group_size = ext4_superblock_get_flex_group_size(sb);
+	if ((bg_ref->index % flex_group_size) == 0) {
+		/* This is the base group */
+		uint32_t i;
+
 		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_index_in_group2blockaddr(sb, 0, bg_ref->index);
-	r += ext4_filesystem_bg_get_backup_blocks(bg_ref);
-
-	if (ext4_filesystem_blockaddr2group(sb, bbmap) != bg_ref->index)
-		bbmap = -1; /* Invalid */
-
-	if (ext4_filesystem_blockaddr2group(sb, ibmap) != bg_ref->index)
-		ibmap = -1;
-
-	while (true) {
-		if (r == bbmap || r == ibmap)
-			r++;
-		else if (r >= itable && r < (itable + itable_sz))
-			r = itable + itable_sz;
-		else
-			break;
-	}
-
-	return r;
+
+		uint32_t total_groups = ext4_superblock_get_block_group_count(sb);
+		for (i = bg_ref->index + 1;
+		    i < min(total_groups, bg_ref->index + flex_group_size); ++i) {
+			r += ext4_filesystem_bg_get_itable_size(sb, i);
+		}
+
+		return r;
+	}
+
+	uint64_t base_addr = ext4_filesystem_index_in_group2blockaddr(sb, 0,
+	    bg_ref->index);
+	uint32_t reserved = ext4_filesystem_bg_get_backup_blocks(bg_ref);
+
+	return base_addr + reserved;
 }
 
Index: uspace/lib/ext4/src/filesystem.c
===================================================================
--- uspace/lib/ext4/src/filesystem.c	(revision 09d1b6fa795d872855bb1d46fc118f64674b45be)
+++ uspace/lib/ext4/src/filesystem.c	(revision 3c8b0a8a677ff6f5ef9864930b02e6aa7dcb0cc6)
@@ -714,6 +714,4 @@
 		/* One for block bitmap one for inode bitmap */
 		free_blocks = free_blocks - reserved - 2 - inode_table_blocks;
-		if (bg_index == 0)
-			++free_blocks; /* XXX Why? */
 
 		ext4_block_group_set_free_blocks_count(bg_ref->block_group,
Index: uspace/lib/ext4/src/ialloc.c
===================================================================
--- uspace/lib/ext4/src/ialloc.c	(revision 09d1b6fa795d872855bb1d46fc118f64674b45be)
+++ uspace/lib/ext4/src/ialloc.c	(revision 3c8b0a8a677ff6f5ef9864930b02e6aa7dcb0cc6)
@@ -176,10 +176,16 @@
 errno_t ext4_ialloc_alloc_inode(ext4_filesystem_t *fs, uint32_t *index, bool is_dir)
 {
+	int pick_first_free = 0;
 	ext4_superblock_t *sb = fs->superblock;
-
-	uint32_t bgid = 0;
-	uint32_t bg_count = ext4_superblock_get_block_group_count(sb);
-	uint32_t sb_free_inodes = ext4_superblock_get_free_inodes_count(sb);
-	uint32_t avg_free_inodes = sb_free_inodes / bg_count;
+	uint32_t bgid;
+	uint32_t sb_free_inodes;
+	uint32_t avg_free_inodes;
+	uint32_t const bg_count = ext4_superblock_get_block_group_count(sb);
+
+retry:
+
+	bgid = 0;
+	sb_free_inodes = ext4_superblock_get_free_inodes_count(sb);
+	avg_free_inodes = sb_free_inodes / bg_count;
 
 	/* Try to find free i-node in all block groups */
@@ -210,6 +216,6 @@
 		 * blocks.
 		 */
-		if (((free_inodes >= avg_free_inodes) || (bgid == bg_count - 1)) &&
-		    (free_blocks > 0)) {
+		if (((free_inodes >= avg_free_inodes) ||
+		    (bgid == bg_count - 1) || pick_first_free) && (free_blocks > 0)) {
 			/* Load block with bitmap */
 			uint32_t bitmap_block_addr = ext4_block_group_get_inode_bitmap(
@@ -307,4 +313,10 @@
 	}
 
+	/* Try again with less strict conditions */
+	if (pick_first_free == 0) {
+		pick_first_free = 1;
+		goto retry;
+	}
+
 	return ENOSPC;
 }
Index: uspace/lib/ext4/src/superblock.c
===================================================================
--- uspace/lib/ext4/src/superblock.c	(revision 09d1b6fa795d872855bb1d46fc118f64674b45be)
+++ uspace/lib/ext4/src/superblock.c	(revision 3c8b0a8a677ff6f5ef9864930b02e6aa7dcb0cc6)
@@ -1315,10 +1315,12 @@
 	    ext4_superblock_get_blocks_per_group(sb);
 	uint64_t total_blocks =
-	    ext4_superblock_get_blocks_count(sb) - 1;
+	    ext4_superblock_get_blocks_count(sb);
+	uint32_t first_block =
+	    ext4_superblock_get_first_data_block(sb);
 
 	if (bgid < block_group_count - 1)
 		return blocks_per_group;
 	else
-		return (total_blocks - ((block_group_count - 1) * blocks_per_group));
+		return (total_blocks - ((block_group_count - 1) * blocks_per_group)) - first_block;
 }
 
@@ -1392,4 +1394,15 @@
 {
 	sb->reserved_gdt_blocks = host2uint32_t_le(n);
+}
+
+/** Get the size of the flex groups
+ *
+ * @param sb	Pointer to the superblock
+ *
+ * @return	Size of the flex groups
+ */
+uint32_t ext4_superblock_get_flex_group_size(ext4_superblock_t *sb)
+{
+	return 2 << sb->log_groups_per_flex;
 }
 
@@ -1465,12 +1478,4 @@
 		 */
 
-		if (idx == 0 && block_size == 1024) {
-			/*
-			 * Special case for first group were the boot block
-			 * resides
-			 */
-			r++;
-		}
-
 		/* This accounts for the superblock */
 		r++;
@@ -1505,5 +1510,5 @@
 	uuid_t uuid;
 	uint32_t cur_ts;
-	uint64_t first_block;
+	uint64_t first_block = 0;
 	uint64_t fs_blocks;
 	uint32_t blocks_count;
@@ -1518,4 +1523,5 @@
 	uint32_t idx;
 	size_t fs_bsize;
+	size_t fs_bsize_log;
 	errno_t rc;
 	struct timespec ts;
@@ -1533,6 +1539,22 @@
 	cur_ts = ts.tv_sec;
 
-	fs_bsize = 1024;
-	first_block = 1; /* 1 for 1k block size, 0 otherwise */
+	fs_bsize = cfg->bsize;
+	switch (fs_bsize) {
+	case 1024:
+		first_block = 1;
+		fs_bsize_log = 0;
+		blocks_group = 8192;
+		break;
+	case 2048:
+		fs_bsize_log = 1;
+		blocks_group = 8192 * 2;
+		break;
+	case 4096:
+		fs_bsize_log = 2;
+		blocks_group = 8192 * 4;
+		break;
+	default:
+		return ENOTSUP;
+	}
 
 	if (fs_bsize % dev_bsize == 0) {
@@ -1543,7 +1565,4 @@
 		fs_blocks = dev_bcnt * (dev_bsize / fs_bsize);
 	}
-
-	/* FS blocks per group */
-	blocks_group = 8 * fs_bsize;
 
 	/* Inodes per group */
@@ -1581,8 +1600,7 @@
 	ext4_superblock_set_free_inodes_count(sb, inodes_count);
 	ext4_superblock_set_first_data_block(sb, first_block);
-	/* Block size will be 1024 bytes */
-	ext4_superblock_set_log_block_size(sb, 0);
+	ext4_superblock_set_log_block_size(sb, fs_bsize_log);
 	/* Fragment size should be equal to block size */
-	ext4_superblock_set_log_frag_size(sb, 0);
+	ext4_superblock_set_log_frag_size(sb, fs_bsize_log);
 	ext4_superblock_set_blocks_per_group(sb, blocks_group);
 	/* Should be the same as blocks per group. */
@@ -1634,5 +1652,4 @@
 	/* Compute free blocks */
 	free_blocks = blocks_count;
-	++free_blocks; // XXX Why?
 	for (idx = 0; idx < ngroups; idx++) {
 		free_blocks -= ext4_superblock_get_group_backup_blocks(sb, idx);
