Index: uspace/lib/crypto/Makefile
===================================================================
--- uspace/lib/crypto/Makefile	(revision 47726b5e33f32673a583b9c6e90c4327cec059fa)
+++ uspace/lib/crypto/Makefile	(revision 6accc5cf7c054d8492fe35203409342ce6f7f5a0)
@@ -33,5 +33,6 @@
 	crypto.c \
 	aes.c \
-	rc4.c
+	rc4.c \
+	crc16_ibm.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/crypto/crc16_ibm.c
===================================================================
--- uspace/lib/crypto/crc16_ibm.c	(revision 6accc5cf7c054d8492fe35203409342ce6f7f5a0)
+++ uspace/lib/crypto/crc16_ibm.c	(revision 6accc5cf7c054d8492fe35203409342ce6f7f5a0)
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2015 Maurizio Lombardi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file crc16_ibm.c
+ *
+ * Implementation of CRC16-IBM (polynomial = 0xA001)
+ *
+ */
+
+#include "crypto.h"
+
+static const uint16_t crct[256] = {
+	0x0000,	0xc0c1,	0xc181,	0x0140,	0xc301,	0x03c0,	0x0280,	0xc241,
+	0xc601,	0x06c0,	0x0780,	0xc741,	0x0500,	0xc5c1,	0xc481,	0x0440,
+	0xcc01,	0x0cc0,	0x0d80,	0xcd41,	0x0f00,	0xcfc1,	0xce81,	0x0e40,
+	0x0a00,	0xcac1,	0xcb81,	0x0b40,	0xc901,	0x09c0,	0x0880,	0xc841,
+	0xd801,	0x18c0,	0x1980,	0xd941,	0x1b00,	0xdbc1,	0xda81,	0x1a40,
+	0x1e00,	0xdec1,	0xdf81,	0x1f40,	0xdd01,	0x1dc0,	0x1c80,	0xdc41,
+	0x1400,	0xd4c1,	0xd581,	0x1540,	0xd701,	0x17c0,	0x1680,	0xd641,
+	0xd201,	0x12c0,	0x1380,	0xd341,	0x1100,	0xd1c1,	0xd081,	0x1040,
+	0xf001,	0x30c0,	0x3180,	0xf141,	0x3300,	0xf3c1,	0xf281,	0x3240,
+	0x3600,	0xf6c1,	0xf781,	0x3740,	0xf501,	0x35c0,	0x3480,	0xf441,
+	0x3c00,	0xfcc1,	0xfd81,	0x3d40,	0xff01,	0x3fc0,	0x3e80,	0xfe41,
+	0xfa01,	0x3ac0,	0x3b80,	0xfb41,	0x3900,	0xf9c1,	0xf881,	0x3840,
+	0x2800,	0xe8c1,	0xe981,	0x2940,	0xeb01,	0x2bc0,	0x2a80,	0xea41,
+	0xee01,	0x2ec0,	0x2f80,	0xef41,	0x2d00,	0xedc1,	0xec81,	0x2c40,
+	0xe401,	0x24c0,	0x2580,	0xe541,	0x2700,	0xe7c1,	0xe681,	0x2640,
+	0x2200,	0xe2c1,	0xe381,	0x2340,	0xe101,	0x21c0,	0x2080,	0xe041,
+	0xa001,	0x60c0,	0x6180,	0xa141,	0x6300,	0xa3c1,	0xa281,	0x6240,
+	0x6600,	0xa6c1,	0xa781,	0x6740,	0xa501,	0x65c0,	0x6480,	0xa441,
+	0x6c00,	0xacc1,	0xad81,	0x6d40,	0xaf01,	0x6fc0,	0x6e80,	0xae41,
+	0xaa01,	0x6ac0,	0x6b80,	0xab41,	0x6900,	0xa9c1,	0xa881,	0x6840,
+	0x7800,	0xb8c1,	0xb981,	0x7940,	0xbb01,	0x7bc0,	0x7a80,	0xba41,
+	0xbe01,	0x7ec0,	0x7f80,	0xbf41,	0x7d00,	0xbdc1,	0xbc81,	0x7c40,
+	0xb401,	0x74c0,	0x7580,	0xb541,	0x7700,	0xb7c1,	0xb681,	0x7640,
+	0x7200,	0xb2c1,	0xb381,	0x7340,	0xb101,	0x71c0,	0x7080,	0xb041,
+	0x5000,	0x90c1,	0x9181,	0x5140,	0x9301,	0x53c0,	0x5280,	0x9241,
+	0x9601,	0x56c0,	0x5780,	0x9741,	0x5500,	0x95c1,	0x9481,	0x5440,
+	0x9c01,	0x5cc0,	0x5d80,	0x9d41,	0x5f00,	0x9fc1,	0x9e81,	0x5e40,
+	0x5a00,	0x9ac1,	0x9b81,	0x5b40,	0x9901,	0x59c0,	0x5880,	0x9841,
+	0x8801,	0x48c0,	0x4980,	0x8941,	0x4b00,	0x8bc1,	0x8a81,	0x4a40,
+	0x4e00,	0x8ec1,	0x8f81,	0x4f40,	0x8d01,	0x4dc0,	0x4c80,	0x8c41,
+	0x4400,	0x84c1,	0x8581,	0x4540,	0x8701,	0x47c0,	0x4680,	0x8641,
+	0x8201,	0x42c0,	0x4380,	0x8341,	0x4100,	0x81c1,	0x8081,	0x4040
+};
+
+/* Compute a CRC16
+ *
+ * @param crc    Init value of the CRC
+ * @param buf    Pointer to the data
+ * @param len    Size of the buffer
+ *
+ * @return       Value of the CRC.
+ */
+uint16_t crc16_ibm(uint16_t crc, uint8_t *buf, size_t len)
+{
+	while (len--) {
+		crc ^= *buf++;
+		crc = (crc >> 8) ^ crct[crc & 0x00FF];
+	}
+
+	return crc;
+}
+
Index: uspace/lib/crypto/crypto.h
===================================================================
--- uspace/lib/crypto/crypto.h	(revision 47726b5e33f32673a583b9c6e90c4327cec059fa)
+++ uspace/lib/crypto/crypto.h	(revision 6accc5cf7c054d8492fe35203409342ce6f7f5a0)
@@ -56,3 +56,5 @@
 extern int pbkdf2(uint8_t *, size_t, uint8_t *, size_t, uint8_t *);
 
+extern uint16_t crc16_ibm(uint16_t crc, uint8_t *buf, size_t len);
+
 #endif
Index: uspace/lib/ext4/Makefile
===================================================================
--- uspace/lib/ext4/Makefile	(revision 47726b5e33f32673a583b9c6e90c4327cec059fa)
+++ uspace/lib/ext4/Makefile	(revision 6accc5cf7c054d8492fe35203409342ce6f7f5a0)
@@ -29,6 +29,6 @@
 USPACE_PREFIX = ../..
 LIBRARY = libext4
-EXTRA_CFLAGS = -I$(LIBBLOCK_PREFIX)
-LIBS = $(LIBBLOCK_PREFIX)/libblock.a
+EXTRA_CFLAGS = -I$(LIBBLOCK_PREFIX) -I$(LIBCRYPTO_PREFIX)
+LIBS = $(LIBBLOCK_PREFIX)/libblock.a $(LIBCRYPTO_PREFIX)/libcrypto.a
 
 SOURCES = \
@@ -36,5 +36,4 @@
 	libext4_bitmap.c \
 	libext4_block_group.c \
-	libext4_crc.c \
 	libext4_directory.c \
 	libext4_directory_index.c \
Index: uspace/lib/ext4/libext4.h
===================================================================
--- uspace/lib/ext4/libext4.h	(revision 47726b5e33f32673a583b9c6e90c4327cec059fa)
+++ uspace/lib/ext4/libext4.h	(revision 6accc5cf7c054d8492fe35203409342ce6f7f5a0)
@@ -37,5 +37,4 @@
 #include "libext4_bitmap.h"
 #include "libext4_block_group.h"
-#include "libext4_crc.h"
 #include "libext4_directory.h"
 #include "libext4_directory_index.h"
Index: uspace/lib/ext4/libext4_balloc.c
===================================================================
--- uspace/lib/ext4/libext4_balloc.c	(revision 47726b5e33f32673a583b9c6e90c4327cec059fa)
+++ uspace/lib/ext4/libext4_balloc.c	(revision 6accc5cf7c054d8492fe35203409342ce6f7f5a0)
@@ -39,27 +39,4 @@
 #include "libext4.h"
 
-/** Compute number of block group from block address.
- *
- * @param sb         Superblock pointer.
- * @param block_addr Absolute address of block.
- *
- * @return Block group index
- *
- */
-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;
-}
-
 /** Free block.
  *
@@ -76,5 +53,5 @@
 	
 	/* Compute indexes */
-	uint32_t block_group = ext4_balloc_get_bgid_of_block(sb, block_addr);
+	uint32_t block_group = ext4_filesystem_blockaddr2group(sb, block_addr);
 	uint32_t index_in_group =
 	    ext4_filesystem_blockaddr2_index_in_group(sb, block_addr);
@@ -135,25 +112,18 @@
 }
 
-/** 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 =
-	    ext4_balloc_get_bgid_of_block(sb, first);
-	uint32_t block_group_last =
-	    ext4_balloc_get_bgid_of_block(sb, first + count - 1);
-	
+	uint32_t block_group_first = ext4_filesystem_blockaddr2group(sb,
+	    first);
+	uint32_t block_group_last = ext4_filesystem_blockaddr2group(sb,
+	    first + count - 1);
+
 	assert(block_group_first == block_group_last);
-	
+
 	/* Load block group reference */
 	ext4_block_group_ref_t *bg_ref;
@@ -161,12 +131,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 +145,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 +157,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 +165,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 +172,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 +180,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 +240,42 @@
     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_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 (1) {
+		if (r == bbmap || r == ibmap)
+			r++;
+		else if (r >= itable && r < (itable + itable_sz))
+			r = itable + itable_sz;
+		else
+			break;
+	}
+
+	return r;
 }
 
@@ -264,12 +291,12 @@
 	*goal = 0;
 	ext4_superblock_t *sb = inode_ref->fs->superblock;
-	
+
 	uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode);
 	uint32_t block_size = ext4_superblock_get_block_size(sb);
 	uint32_t inode_block_count = inode_size / block_size;
-	
+
 	if (inode_size % block_size != 0)
 		inode_block_count++;
-	
+
 	/* If inode has some blocks, get last block address + 1 */
 	if (inode_block_count > 0) {
@@ -278,18 +305,16 @@
 		if (rc != EOK)
 			return rc;
-		
+
 		if (goal != 0) {
 			(*goal)++;
 			return EOK;
 		}
-		
 		/* If goal == 0, sparse file -> continue */
 	}
-	
+
 	/* Identify block group of inode */
 	uint32_t inodes_per_group = ext4_superblock_get_inodes_per_group(sb);
 	uint32_t block_group = (inode_ref->index - 1) / inodes_per_group;
-	block_size = ext4_superblock_get_block_size(sb);
-	
+
 	/* Load block group reference */
 	ext4_block_group_ref_t *bg_ref;
@@ -298,30 +323,7 @@
 	if (rc != EOK)
 		return rc;
-	
-	/* Compute indexes */
-	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 inode_table_bytes;
-	
-	/* Check for last block group */
-	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(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++;
-	
-	*goal = inode_table_first_block + inode_table_blocks;
-	
+
+	*goal = ext4_balloc_get_first_data_block_in_group(sb, bg_ref);
+
 	return ext4_filesystem_put_block_group_ref(bg_ref);
 }
@@ -353,5 +355,5 @@
 	
 	/* Load block group number for goal and relative index */
-	uint32_t block_group = ext4_balloc_get_bgid_of_block(sb, goal);
+	uint32_t block_group = ext4_filesystem_blockaddr2group(sb, goal);
 	uint32_t index_in_group =
 	    ext4_filesystem_blockaddr2_index_in_group(sb, goal);
@@ -626,5 +628,5 @@
 	
 	/* Compute indexes */
-	uint32_t block_group = ext4_balloc_get_bgid_of_block(sb, fblock);
+	uint32_t block_group = ext4_filesystem_blockaddr2group(sb, fblock);
 	uint32_t index_in_group =
 	    ext4_filesystem_blockaddr2_index_in_group(sb, fblock);
Index: uspace/lib/ext4/libext4_crc.c
===================================================================
--- uspace/lib/ext4/libext4_crc.c	(revision 47726b5e33f32673a583b9c6e90c4327cec059fa)
+++ 	(revision )
@@ -1,47 +1,0 @@
-/*
- * Copyright (c) 2012 Frantisek Princ
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup libext4
- * @{
- */
-
-/**
- * @file  libext4_crc.c
- */
-
-#include "libext4.h"
-
-uint16_t crc16(uint16_t crc, const uint8_t *buffer, size_t len)
-{
-	// TODO
-	return 0;
-}
-
-/**
- * @}
- */
Index: uspace/lib/ext4/libext4_crc.h
===================================================================
--- uspace/lib/ext4/libext4_crc.h	(revision 47726b5e33f32673a583b9c6e90c4327cec059fa)
+++ 	(revision )
@@ -1,42 +1,0 @@
-/*
- * Copyright (c) 2012 Frantisek Princ
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup libext4
- * @{
- */
-
-#ifndef LIBEXT4_LIBEXT4_CRC_H_
-#define LIBEXT4_LIBEXT4_CRC_H_
-
-extern uint16_t crc16(uint16_t, const uint8_t *, size_t);
-
-#endif
-
-/**
- * @}
- */
Index: uspace/lib/ext4/libext4_filesystem.c
===================================================================
--- uspace/lib/ext4/libext4_filesystem.c	(revision 47726b5e33f32673a583b9c6e90c4327cec059fa)
+++ uspace/lib/ext4/libext4_filesystem.c	(revision 6accc5cf7c054d8492fe35203409342ce6f7f5a0)
@@ -40,4 +40,6 @@
 #include <malloc.h>
 #include <ipc/vfs.h>
+#include <align.h>
+#include <crypto.h>
 #include "libext4.h"
 
@@ -53,4 +55,5 @@
     enum cache_mode cmode)
 {
+	int rc;
 	ext4_superblock_t *temp_superblock = NULL;
 
@@ -58,5 +61,5 @@
 
 	/* Initialize block library (4096 is size of communication channel) */
-	int rc = block_init(EXCHANGE_SERIALIZE, fs->device, 4096);
+	rc = block_init(EXCHANGE_SERIALIZE, fs->device, 4096);
 	if (rc != EOK)
 		goto err;
@@ -139,5 +142,5 @@
 	/* Release memory space for superblock */
 	free(fs->superblock);
-	
+
 	/* Finish work with block library */
 	block_cache_fini(fs->device);
@@ -250,4 +253,19 @@
 }
 
+/** 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);
+	uint32_t first_block = ext4_superblock_get_first_data_block(sb);
+
+	return (b - first_block) / blocks_per_group;
+}
+
 /** Initialize block bitmap in block group.
  *
@@ -259,6 +277,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);
 	
@@ -272,19 +297,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;
 	
@@ -423,5 +469,5 @@
 	}
 	
-	/* Inititialize in-memory representation */
+	/* Initialize in-memory representation */
 	newref->block_group = newref->block->data + offset;
 	newref->fs = fs;
@@ -488,5 +534,5 @@
 	/* If checksum not supported, 0 will be returned */
 	uint16_t crc = 0;
-	
+
 	/* Compute the checksum only if the filesystem supports it */
 	if (ext4_superblock_has_feature_read_only(sb,
@@ -501,11 +547,11 @@
 		
 		/* Initialization */
-		crc = crc16(~0, sb->uuid, sizeof(sb->uuid));
+		crc = crc16_ibm(~0, sb->uuid, sizeof(sb->uuid));
 		
 		/* Include index of block group */
-		crc = crc16(crc, (uint8_t *) &le_group, sizeof(le_group));
+		crc = crc16_ibm(crc, (uint8_t *) &le_group, sizeof(le_group));
 		
 		/* Compute crc from the first part (stop before checksum field) */
-		crc = crc16(crc, (uint8_t *) bg, offset);
+		crc = crc16_ibm(crc, (uint8_t *) bg, offset);
 		
 		/* Skip checksum */
@@ -516,5 +562,5 @@
 		    EXT4_FEATURE_INCOMPAT_64BIT)) &&
 		    (offset < ext4_superblock_get_desc_size(sb)))
-			crc = crc16(crc, ((uint8_t *) bg) + offset,
+			crc = crc16_ibm(crc, ((uint8_t *) bg) + offset,
 			    ext4_superblock_get_desc_size(sb) - offset);
 	}
@@ -523,7 +569,130 @@
 }
 
+/** 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)
+{
+	if (p == 1 && n != p)
+		return false;
+
+	while (n != p) {
+		if (n < p)
+			return false;
+		else if ((n % p) != 0)
+			return false;
+
+		n /= p;
+	}
+
+	return true;
+}
+
+/** Get the number of blocks used by superblock + gdt + reserved gdt backups
+ *
+ * @param bg    Pointer to block group
+ *
+ * @return      Number of blocks
+ */
+uint32_t ext4_filesystem_bg_get_backup_blocks(ext4_block_group_ref_t *bg)
+{
+	uint32_t const idx = bg->index;
+	uint32_t r = 0;
+	bool has_backups = false;
+	ext4_superblock_t *sb = bg->fs->superblock;
+
+	/* First step: determine if the block group contains the backups */
+
+	if (idx <= 1)
+		has_backups = true;
+	else {
+		if (ext4_superblock_has_feature_compatible(sb,
+		    EXT4_FEATURE_COMPAT_SPARSE_SUPER2)) {
+			uint32_t g1, g2;
+
+			ext4_superblock_get_backup_groups_sparse2(sb,
+			    &g1, &g2);
+
+			if (idx == g1 || idx == g2)
+				has_backups = true;
+		} else if (!ext4_superblock_has_feature_read_only(sb,
+		    EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
+			/* Very old fs were all block groups have
+			 * superblock and block descriptors backups.
+			 */
+			has_backups = true;
+		} else {
+			if ((idx & 1) && (is_power_of(idx, 3) ||
+			    is_power_of(idx, 5) || is_power_of(idx, 7)))
+				has_backups = true;
+		}
+	}
+
+	if (has_backups) {
+		uint32_t bg_count;
+		uint32_t bg_desc_sz;
+		uint32_t gdt_table; /* Size of the GDT in blocks */
+		uint32_t block_size = ext4_superblock_get_block_size(sb);
+
+		/* Now we know that this block group has backups,
+		 * we have to compute how many blocks are reserved
+		 * for them
+		 */
+
+		if (idx == 0 && block_size == 1024) {
+			/* Special case for first group were the boot block
+			 * resides
+			 */
+			r++;
+		}
+
+		/* This accounts for the superblock */
+		r++;
+
+		/* Add the number of blocks used for the GDT */
+		bg_count = ext4_superblock_get_block_group_count(sb);
+		bg_desc_sz = ext4_superblock_get_desc_size(sb);
+		gdt_table = ROUND_UP(bg_count * bg_desc_sz, block_size) /
+		    block_size;
+
+		r += gdt_table;
+
+		/* And now the number of reserved GDT blocks */
+		r += ext4_superblock_get_reserved_gdt_blocks(sb);
+	}
+
+	return r;
+}
+
 /** Put reference to block group.
  *
- * @oaram ref Pointer for reference to be put back
+ * @param ref Pointer for reference to be put back
  *
  * @return Error code
Index: uspace/lib/ext4/libext4_filesystem.h
===================================================================
--- uspace/lib/ext4/libext4_filesystem.h	(revision 47726b5e33f32673a583b9c6e90c4327cec059fa)
+++ uspace/lib/ext4/libext4_filesystem.h	(revision 6accc5cf7c054d8492fe35203409342ce6f7f5a0)
@@ -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,4 +65,7 @@
 extern int ext4_filesystem_append_inode_block(ext4_inode_ref_t *, uint32_t *,
     uint32_t *);
+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_superblock.c
===================================================================
--- uspace/lib/ext4/libext4_superblock.c	(revision 47726b5e33f32673a583b9c6e90c4327cec059fa)
+++ uspace/lib/ext4/libext4_superblock.c	(revision 6accc5cf7c054d8492fe35203409342ce6f7f5a0)
@@ -1298,4 +1298,52 @@
 }
 
+/** Get the backup groups used with SPARSE_SUPER2
+ *
+ * @param sb    Pointer to the superblock
+ * @param g1    Output pointer to the first backup group
+ * @param g2    Output pointer to the second backup group
+ */
+void ext4_superblock_get_backup_groups_sparse2(ext4_superblock_t *sb,
+    uint32_t *g1, uint32_t *g2)
+{
+	*g1 = uint32_t_le2host(sb->backup_bgs[0]);
+	*g2 = uint32_t_le2host(sb->backup_bgs[1]);
+}
+
+/** Set the backup groups (SPARSE SUPER2)
+ *
+ * @param sb    Pointer to the superblock
+ * @param g1    Index of the first group
+ * @param g2    Index of the second group
+ */
+void ext4_superblock_set_backup_groups_sparse2(ext4_superblock_t *sb,
+    uint32_t g1, uint32_t g2)
+{
+	sb->backup_bgs[0] = host2uint32_t_le(g1);
+	sb->backup_bgs[1] = host2uint32_t_le(g2);
+}
+
+/** Get the number of blocks (per group) reserved to GDT expansion
+ *
+ * @param sb    Pointer to the superblock
+ *
+ * @return      Number of blocks
+ */
+uint32_t ext4_superblock_get_reserved_gdt_blocks(ext4_superblock_t *sb)
+{
+	return uint32_t_le2host(sb->reserved_gdt_blocks);
+}
+
+/** Set the number of blocks (per group) reserved to GDT expansion
+ *
+ * @param sb    Pointer to the superblock
+ * @param n     Number of reserved blocks
+ */
+void ext4_superblock_set_reserved_gdt_blocks(ext4_superblock_t *sb,
+    uint32_t n)
+{
+	sb->reserved_gdt_blocks = host2uint32_t_le(n);
+}
+
 /**
  * @}
Index: uspace/lib/ext4/libext4_superblock.h
===================================================================
--- uspace/lib/ext4/libext4_superblock.h	(revision 47726b5e33f32673a583b9c6e90c4327cec059fa)
+++ uspace/lib/ext4/libext4_superblock.h	(revision 6accc5cf7c054d8492fe35203409342ce6f7f5a0)
@@ -135,4 +135,13 @@
 extern void ext4_superblock_set_flags(ext4_superblock_t *, uint32_t);
 
+extern void ext4_superblock_get_backup_groups_sparse2(ext4_superblock_t *sb,
+    uint32_t *g1, uint32_t *g2);
+extern void ext4_superblock_set_backup_groups_sparse2(ext4_superblock_t *sb,
+    uint32_t g1, uint32_t g2);
+
+extern uint32_t ext4_superblock_get_reserved_gdt_blocks(ext4_superblock_t *sb);
+extern void ext4_superblock_set_reserved_gdt_blocks(ext4_superblock_t *sb,
+    uint32_t n);
+
 /* More complex superblock functions */
 extern bool ext4_superblock_has_flag(ext4_superblock_t *, uint32_t);
Index: uspace/lib/ext4/libext4_types.h
===================================================================
--- uspace/lib/ext4/libext4_types.h	(revision 47726b5e33f32673a583b9c6e90c4327cec059fa)
+++ uspace/lib/ext4/libext4_types.h	(revision 6accc5cf7c054d8492fe35203409342ce6f7f5a0)
@@ -83,7 +83,7 @@
 	 * happen if the EXT4_FEATURE_COMPAT_DIR_PREALLOC flag is on.
 	 */
-	uint8_t s_prealloc_blocks;       /* Number of blocks to try to preallocate */
-	uint8_t s_prealloc_dir_blocks;   /* Number to preallocate for dirs */
-	uint16_t s_reserved_gdt_blocks;  /* Per group desc for online growth */
+	uint8_t prealloc_blocks;        /* Number of blocks to try to preallocate */
+	uint8_t prealloc_dir_blocks;    /* Number to preallocate for dirs */
+	uint16_t reserved_gdt_blocks;   /* Per group desc for online growth */
 	
 	/*
@@ -133,6 +133,11 @@
 	uint64_t last_error_block;          /* Block involved of last error */
 	uint8_t last_error_func[32];        /* Function where the error happened */
-	uint8_t mount_opts[64];
-	uint32_t padding[112];              /* Padding to the end of the block */
+	uint8_t mount_opts[64];             /* String containing the mount options */
+	uint32_t usr_quota_inum;            /* Inode number of user quota file */
+	uint32_t grp_quota_inum;            /* Inode number of group quota file */
+	uint32_t overhead_blocks;           /* Overhead blocks/clusters */
+	uint32_t backup_bgs[2];             /* Block groups containing superblock backups (if SPARSE_SUPER2) */
+	uint32_t encrypt_algos;             /* Encrypt algorithm in use */
+	uint32_t padding[105];              /* Padding to the end of the block */
 } __attribute__((packed)) ext4_superblock_t;
 
@@ -176,4 +181,5 @@
 #define EXT4_FEATURE_COMPAT_RESIZE_INODE   0x0010
 #define EXT4_FEATURE_COMPAT_DIR_INDEX      0x0020
+#define EXT4_FEATURE_COMPAT_SPARSE_SUPER2  0x0200
 
 /*
@@ -208,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 \
Index: uspace/srv/fs/ext4fs/Makefile
===================================================================
--- uspace/srv/fs/ext4fs/Makefile	(revision 47726b5e33f32673a583b9c6e90c4327cec059fa)
+++ uspace/srv/fs/ext4fs/Makefile	(revision 6accc5cf7c054d8492fe35203409342ce6f7f5a0)
@@ -28,6 +28,7 @@
 
 USPACE_PREFIX = ../../..
-LIBS = $(LIBBLOCK_PREFIX)/libblock.a $(LIBFS_PREFIX)/libfs.a $(LIBEXT4_PREFIX)/libext4.a
-EXTRA_CFLAGS += -I$(LIBBLOCK_PREFIX) -I$(LIBFS_PREFIX) -I$(LIBEXT4_PREFIX)
+LIBS = $(LIBBLOCK_PREFIX)/libblock.a $(LIBFS_PREFIX)/libfs.a \
+    $(LIBEXT4_PREFIX)/libext4.a $(LIBCRYPTO_PREFIX)/libcrypto.a
+EXTRA_CFLAGS += -I$(LIBBLOCK_PREFIX) -I$(LIBFS_PREFIX) -I$(LIBEXT4_PREFIX) -I$(LIBCRYPTO_PREFIX)
 BINARY = ext4fs
 STATIC_NEEDED = y
