FEATURES:
authorgkostka <kostka.grzegorz@gmail.com>
Thu, 24 Oct 2013 21:21:19 +0000 (21:21 +0000)
committergkostka <kostka.grzegorz@gmail.com>
Thu, 24 Oct 2013 21:21:19 +0000 (21:21 +0000)
 - extent support
 - block group crc support
 - extent and directory indexing is enabled by default
 - new images (100MB ext2, ext3, ext4)
 - fs features debug in ext4_fs.c
 - new demo app features

BUGFIX:
 - ext4_inode_get_blocks_count fix

demos/generic/main.c
ext_images.7z
lwext4/ext4_block_group.c
lwext4/ext4_config.h
lwext4/ext4_debug.h
lwext4/ext4_extent.c [new file with mode: 0644]
lwext4/ext4_extent.h [new file with mode: 0644]
lwext4/ext4_fs.c
lwext4/ext4_inode.c

index ab24bd753b885bbca3ff24fe96e35c8c74250bc6..e6e1f39013936f25f50ddf4846ffd1b15f430922 100644 (file)
 #include <ext4_filedev.h>\r
 #include <ext4.h>\r
 \r
-\r
-\r
 char input_name[128] = "ext2";\r
 \r
 /**@brief      Read-write size*/\r
 static int rw_szie  = 1024;\r
 \r
 /**@brief      Read-write size*/\r
-static int rw_count = 1024;\r
+static int rw_count = 10000;\r
 \r
 /**@brief   Directory test count*/\r
 static int dir_cnt  = 10;\r
 \r
+/**@brief   Static or dynamic cache mode*/\r
 static bool cache_mode = false;\r
 \r
+/**@brief   Cleanup after test.*/\r
+static bool cleanup_flag = false;\r
+\r
+/**@brief   Block device stats.*/\r
+static bool bstat = false;\r
+\r
+/**@brief   Superblock stats.*/\r
+static bool sbstat = false;\r
 \r
 /**@brief      File write buffer*/\r
 static uint8_t *wr_buff;\r
@@ -70,9 +77,12 @@ Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)       \n\
 Usage:                                                                                                                 \n\\r
        -i   - input file             (default = ext2)                          \n\\r
        -rws - single R/W size        (default = 1024)                          \n\\r
-       -rwc - R/W count              (default = 1024)                          \n\\r
-       -cache - 0 static, 1 dynamic  (default = 0)                                     \n\\r
-    -dirs  - directory test count (default = 0)                 \n\\r
+       -rwc - R/W count              (default = 10000)                         \n\\r
+       -cache  - 0 static, 1 dynamic  (default = 0)                \n\\r
+    -dirs   - directory test count (default = 10)               \n\\r
+    -clean  - clean up after test                               \n\\r
+    -bstat  - block device stats                                \n\\r
+    -sbstat - superblock stats                                  \n\\r
 \n";\r
 \r
 static char* entry_to_str(uint8_t type)\r
@@ -192,10 +202,6 @@ static bool dir_test(int len)
     int       i;\r
     char path[64];\r
 \r
-    printf("Remove directory /mp/dir1\n");\r
-    ext4_dir_rm("/mp/dir1");\r
-\r
-\r
     printf("Directory create: /mp/dir1\n");\r
     r = ext4_dir_mk("/mp/dir1");\r
     if(r != EOK){\r
@@ -214,31 +220,17 @@ static bool dir_test(int len)
         }\r
     }\r
 \r
-    printf("Add directories to: /mp/dir1\n");\r
-    for (i = 0; i < len; ++i) {\r
-        sprintf(path, "/mp/dir1/d%d", i);\r
-        r = ext4_dir_mk(path);\r
-        if(r != EOK){\r
-            printf("Unable to create directory in directory: /mp/dir1\n");\r
-            return false;\r
-        }\r
-    }\r
-\r
-    printf("Add file directories in: /mp/dir1\n");\r
-\r
-    for (i = 0; i < len; ++i) {\r
-        sprintf(path, "/mp/dir1/d%d/ff", i);\r
-        r = ext4_fopen(&f, path, "wb");\r
-        if(r != EOK){\r
-            printf("Unable to create file in directory: /mp/dir1\n");\r
-            return false;\r
-        }\r
-    }\r
-\r
     dir_ls("/mp/dir1");\r
     return true;\r
 }\r
 \r
+static void cleanup(void)\r
+{\r
+    ext4_fremove("/mp/hello.txt");\r
+    ext4_fremove("/mp/test1");\r
+    ext4_dir_rm("/mp/dir1");\r
+}\r
+\r
 int main(int argc, char **argv)\r
 {\r
        int option_index = 0;\r
@@ -254,11 +246,14 @@ int main(int argc, char **argv)
         {"rws",     required_argument, 0, 'b'},\r
         {"rwc",                required_argument, 0, 'c'},\r
         {"cache",   required_argument, 0, 'd'},\r
-        {"dirs",   required_argument,  0, 'e'},\r
+        {"dirs",    required_argument, 0, 'e'},\r
+        {"clean",   no_argument,       0, 'f'},\r
+        {"bstat",   no_argument,       0, 'g'},\r
+        {"sbstat",  no_argument,       0, 'h'},\r
         {0, 0, 0, 0}\r
       };\r
 \r
-    while(-1 != (c = getopt_long (argc, argv, "a:b:c:d:e:", long_options, &option_index))) {\r
+    while(-1 != (c = getopt_long (argc, argv, "a:b:c:d:e:fgh", long_options, &option_index))) {\r
 \r
        switch(c){\r
                case 'a':\r
@@ -276,6 +271,15 @@ int main(int argc, char **argv)
             case 'e':\r
                 dir_cnt = atoi(optarg);\r
                 break;\r
+            case 'f':\r
+                cleanup_flag = true;\r
+                break;\r
+            case 'g':\r
+                bstat = true;\r
+                break;\r
+            case 'h':\r
+                sbstat = true;\r
+                break;\r
                default:\r
                        printf(usage);\r
                        return EXIT_FAILURE;\r
@@ -323,12 +327,14 @@ int main(int argc, char **argv)
                return EXIT_FAILURE;\r
        }\r
 \r
-       dir_test(dir_cnt);\r
+       cleanup();\r
+\r
+    if(sbstat)\r
+        mp_stats();\r
 \r
-       ext4_fremove("/mp/hello.txt");\r
-       ext4_fremove("/mp/test1");\r
-       mp_stats();\r
-       dir_ls("/mp/");\r
+\r
+    dir_ls("/mp/");\r
+       dir_test(dir_cnt);\r
 \r
     /*Add hello world file.*/\r
     r = ext4_fopen(&f, "/mp/hello.txt", "wb");\r
@@ -390,16 +396,20 @@ int main(int argc, char **argv)
        }\r
 \r
        printf("OK\n");\r
-\r
        r = ext4_fclose(&f);\r
 \r
-\r
-       mp_stats();\r
        dir_ls("/mp/");\r
 \r
-       block_stats();\r
-       r = ext4_umount("/mp/");\r
+       if(sbstat)\r
+           mp_stats();\r
+\r
+       if(bstat)\r
+           block_stats();\r
 \r
+       if(cleanup_flag)\r
+           cleanup();\r
+\r
+       r = ext4_umount("/mp/");\r
        printf("Test finish: OK\n");\r
     return EXIT_SUCCESS;\r
 \r
index 375a3baa9cf3f60811f724e7be12da90a1edf073..c7a629c93baa4d157e42a23586d0621b76a16e88 100644 (file)
Binary files a/ext_images.7z and b/ext_images.7z differ
index d5def32d30f8b7756ffc38c82d5bc3a764f223e9..8da606c9b38df1e07f9d1aec6ed0ac0a4069d187 100644 (file)
 #include <ext4_block_group.h>
 
 
+static uint16_t const crc16_tab[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
+};
 
 uint16_t ext4_bg_crc16(uint16_t crc, const uint8_t *buffer, size_t len)
 {
-    // TODO
-    return 0;
+    while (len--)
+
+        crc = (((crc >> 8) & 0xffU) ^
+               crc16_tab[(crc ^ *buffer++) & 0xffU]) & 0x0000ffffU;
+    return crc;
 }
 
 /**
index 45d353c05cf1644049e4b4e8c97f718988c3d86f..5080256c54514a59ac29362abaac080212b38c34 100644 (file)
 
 /**@brief      Enable directory indexing feature (EXT3 feature)*/
 #ifndef CONFIG_DIR_INDEX_ENABLE
-#define CONFIG_DIR_INDEX_ENABLE                                0
+#define CONFIG_DIR_INDEX_ENABLE                                1
 #endif
 
 /**@brief      Enable extents feature (EXT4 feature)*/
 #ifndef CONFIG_EXTENT_ENABLE
-#define CONFIG_EXTENT_ENABLE                           0
+#define CONFIG_EXTENT_ENABLE                           1
 #endif
 
 
index 59414625a0931cdd60f44923e55bcd9503420ba2..5a8abb760f0c76767df1b467d9b7ceb451d9739e 100644 (file)
 /**@brief      Debug mask: ext4_bcache.c*/
 #define EXT4_DEBUG_BCACHE                      (1 << 9)
 
+/**@brief   Debug mask: ext4_extents.c*/
+#define EXT4_DEBUG_EXTENTS          (1 << 10)
+
+
 
 /**@brief      All debug printf enabled.*/
 #define EXT4_DEBUG_ALL                         (0xFFFFFFFF)
diff --git a/lwext4/ext4_extent.c b/lwext4/ext4_extent.c
new file mode 100644 (file)
index 0000000..ca1a636
--- /dev/null
@@ -0,0 +1,935 @@
+/*\r
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)\r
+ *\r
+ *\r
+ * HelenOS:\r
+ * Copyright (c) 2012 Martin Sucha\r
+ * Copyright (c) 2012 Frantisek Princ\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions\r
+ * are met:\r
+ *\r
+ * - Redistributions of source code must retain the above copyright\r
+ *   notice, this list of conditions and the following disclaimer.\r
+ * - Redistributions in binary form must reproduce the above copyright\r
+ *   notice, this list of conditions and the following disclaimer in the\r
+ *   documentation and/or other materials provided with the distribution.\r
+ * - The name of the author may not be used to endorse or promote products\r
+ *   derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+\r
+/** @addtogroup lwext4\r
+ * @{\r
+ */\r
+/**\r
+ * @file  ext4_extent.c\r
+ * @brief More complex filesystem functions.\r
+ */\r
+\r
+#include <ext4_config.h>\r
+#include <ext4_extent.h>\r
+#include <ext4_inode.h>\r
+#include <ext4_super.h>\r
+#include <ext4_blockdev.h>\r
+#include <ext4_balloc.h>\r
+\r
+#include <string.h>\r
+#include <stdlib.h>\r
+\r
+uint32_t ext4_extent_get_first_block(struct ext4_extent *extent)\r
+{\r
+    return to_le32(extent->first_block);\r
+}\r
+\r
+\r
+void ext4_extent_set_first_block(struct ext4_extent *extent, uint32_t iblock)\r
+{\r
+    extent->first_block = to_le32(iblock);\r
+}\r
+\r
+\r
+uint16_t ext4_extent_get_block_count(struct ext4_extent *extent)\r
+{\r
+    return to_le16(extent->block_count);\r
+}\r
+\r
+\r
+void ext4_extent_set_block_count(struct ext4_extent *extent, uint16_t count)\r
+{\r
+    extent->block_count = to_le16(count);\r
+}\r
+\r
+\r
+uint64_t ext4_extent_get_start(struct ext4_extent *extent)\r
+{\r
+    return ((uint64_t)to_le16(extent->start_hi)) << 32 |\r
+        ((uint64_t)to_le32(extent->start_lo));\r
+}\r
+\r
+\r
+void ext4_extent_set_start(struct ext4_extent *extent, uint64_t fblock)\r
+{\r
+    extent->start_lo = to_le32((fblock << 32) >> 32);\r
+    extent->start_hi = to_le16((uint16_t)(fblock >> 32));\r
+}\r
+\r
+\r
+uint32_t ext4_extent_index_get_first_block(struct ext4_extent_index *index)\r
+{\r
+    return to_le32(index->first_block);\r
+}\r
+\r
+\r
+void ext4_extent_index_set_first_block(struct ext4_extent_index *index,\r
+    uint32_t iblock)\r
+{\r
+    index->first_block = to_le32(iblock);\r
+}\r
+\r
+\r
+uint64_t ext4_extent_index_get_leaf(struct ext4_extent_index *index)\r
+{\r
+    return ((uint64_t) to_le16(index->leaf_hi)) << 32 |\r
+        ((uint64_t)to_le32(index->leaf_lo));\r
+}\r
+\r
+void ext4_extent_index_set_leaf(struct ext4_extent_index *index,\r
+    uint64_t fblock)\r
+{\r
+    index->leaf_lo = to_le32((fblock << 32) >> 32);\r
+    index->leaf_hi = to_le16((uint16_t) (fblock >> 32));\r
+}\r
+\r
+\r
+uint16_t ext4_extent_header_get_magic(struct ext4_extent_header *header)\r
+{\r
+    return to_le16(header->magic);\r
+}\r
+\r
+\r
+void ext4_extent_header_set_magic(struct ext4_extent_header *header,\r
+    uint16_t magic)\r
+{\r
+    header->magic = to_le16(magic);\r
+}\r
+\r
+\r
+uint16_t ext4_extent_header_get_entries_count(struct ext4_extent_header *header)\r
+{\r
+    return to_le16(header->entries_count);\r
+}\r
+\r
+\r
+void ext4_extent_header_set_entries_count(struct ext4_extent_header *header,\r
+    uint16_t count)\r
+{\r
+    header->entries_count = to_le16(count);\r
+}\r
+\r
+\r
+uint16_t ext4_extent_header_get_max_entries_count(struct ext4_extent_header *header)\r
+{\r
+    return to_le16(header->max_entries_count);\r
+}\r
+\r
+\r
+void ext4_extent_header_set_max_entries_count(struct ext4_extent_header *header,\r
+    uint16_t max_count)\r
+{\r
+    header->max_entries_count = to_le16(max_count);\r
+}\r
+\r
+\r
+uint16_t ext4_extent_header_get_depth(struct ext4_extent_header *header)\r
+{\r
+    return to_le16(header->depth);\r
+}\r
+\r
+\r
+void ext4_extent_header_set_depth(struct ext4_extent_header *header,\r
+    uint16_t depth)\r
+{\r
+    header->depth = to_le16(depth);\r
+}\r
+\r
+\r
+uint32_t ext4_extent_header_get_generation(struct ext4_extent_header *header)\r
+{\r
+    return to_le32(header->generation);\r
+}\r
+\r
+\r
+void ext4_extent_header_set_generation(struct ext4_extent_header *header,\r
+    uint32_t generation)\r
+{\r
+    header->generation = to_le32(generation);\r
+}\r
+\r
+/**@brief Binary search in extent index node.\r
+ * @param header Extent header of index node\r
+ * @param index  Output value - found index will be set here\r
+ * @param iblock Logical block number to find in index node */\r
+static void ext4_extent_binsearch_idx(struct ext4_extent_header *header,\r
+    struct ext4_extent_index **index, uint32_t iblock)\r
+{\r
+    struct ext4_extent_index *r;\r
+    struct ext4_extent_index *l;\r
+    struct ext4_extent_index *m;\r
+\r
+    uint16_t entries_count =\r
+        ext4_extent_header_get_entries_count(header);\r
+\r
+    /* Initialize bounds */\r
+    l = EXT4_EXTENT_FIRST_INDEX(header) + 1;\r
+    r = EXT4_EXTENT_FIRST_INDEX(header) + entries_count - 1;\r
+\r
+    /* Do binary search */\r
+    while (l <= r) {\r
+        m = l + (r - l) / 2;\r
+        uint32_t first_block = ext4_extent_index_get_first_block(m);\r
+\r
+        if (iblock < first_block)\r
+            r = m - 1;\r
+        else\r
+            l = m + 1;\r
+    }\r
+\r
+    /* Set output value */\r
+    *index = l - 1;\r
+}\r
+\r
+/**@brief Binary search in extent leaf node.\r
+ * @param header Extent header of leaf node\r
+ * @param extent Output value - found extent will be set here,\r
+ *               or NULL if node is empty\r
+ * @param iblock Logical block number to find in leaf node */\r
+static void ext4_extent_binsearch(struct ext4_extent_header *header,\r
+    struct ext4_extent **extent, uint32_t iblock)\r
+{\r
+    struct ext4_extent *r;\r
+    struct ext4_extent *l;\r
+    struct ext4_extent *m;\r
+\r
+    uint16_t entries_count =\r
+        ext4_extent_header_get_entries_count(header);\r
+\r
+    if (entries_count == 0) {\r
+        /* this leaf is empty */\r
+        *extent = NULL;\r
+        return;\r
+    }\r
+\r
+    /* Initialize bounds */\r
+    l = EXT4_EXTENT_FIRST(header) + 1;\r
+    r = EXT4_EXTENT_FIRST(header) + entries_count - 1;\r
+\r
+    /* Do binary search */\r
+    while (l <= r) {\r
+        m = l + (r - l) / 2;\r
+        uint32_t first_block = ext4_extent_get_first_block(m);\r
+\r
+        if (iblock < first_block)\r
+            r = m - 1;\r
+        else\r
+            l = m + 1;\r
+    }\r
+\r
+    /* Set output value */\r
+    *extent = l - 1;\r
+}\r
+\r
+\r
+int ext4_extent_find_block(struct ext4_inode_ref *inode_ref, uint32_t iblock,\r
+    uint32_t *fblock)\r
+{\r
+    /* Compute bound defined by i-node size */\r
+    uint64_t inode_size =\r
+        ext4_inode_get_size(&inode_ref->fs->sb, inode_ref->inode);\r
+\r
+    uint32_t block_size =\r
+        ext4_sb_get_block_size(&inode_ref->fs->sb);\r
+\r
+    uint32_t last_idx = (inode_size - 1) / block_size;\r
+\r
+    /* Check if requested iblock is not over size of i-node */\r
+    if (iblock > last_idx) {\r
+        *fblock = 0;\r
+        return EOK;\r
+    }\r
+\r
+    struct ext4_block block;\r
+    block.lb_id = 0;\r
+\r
+    /* Walk through extent tree */\r
+    struct ext4_extent_header *header =\r
+        ext4_inode_get_extent_header(inode_ref->inode);\r
+\r
+    while (ext4_extent_header_get_depth(header) != 0) {\r
+        /* Search index in node */\r
+        struct ext4_extent_index *index;\r
+        ext4_extent_binsearch_idx(header, &index, iblock);\r
+\r
+        /* Load child node and set values for the next iteration */\r
+        uint64_t child = ext4_extent_index_get_leaf(index);\r
+\r
+        if (block.lb_id)\r
+            ext4_block_set(inode_ref->fs->bdev, &block);\r
+\r
+\r
+        int rc = ext4_block_get(inode_ref->fs->bdev, &block, child);\r
+        if (rc != EOK)\r
+            return rc;\r
+\r
+        header = (struct ext4_extent_header *)block.data;\r
+    }\r
+\r
+    /* Search extent in the leaf block */\r
+    struct ext4_extent* extent = NULL;\r
+    ext4_extent_binsearch(header, &extent, iblock);\r
+\r
+    /* Prevent empty leaf */\r
+    if (extent == NULL) {\r
+        *fblock = 0;\r
+    } else {\r
+        /* Compute requested physical block address */\r
+        uint32_t phys_block;\r
+        uint32_t first = ext4_extent_get_first_block(extent);\r
+        phys_block = ext4_extent_get_start(extent) + iblock - first;\r
+\r
+        *fblock = phys_block;\r
+    }\r
+\r
+    /* Cleanup */\r
+    if (block.lb_id)\r
+        ext4_block_set(inode_ref->fs->bdev, &block);\r
+\r
+    return EOK;\r
+}\r
+\r
+/**@brief Find extent for specified iblock.\r
+ * This function is used for finding block in the extent tree with\r
+ * saving the path through the tree for possible future modifications.\r
+ * @param inode_ref I-node to read extent tree from\r
+ * @param iblock    Iblock to find extent for\r
+ * @param ret_path  Output value for loaded path from extent tree\r
+ * @return Error code */\r
+static int ext4_extent_find_extent(struct ext4_inode_ref *inode_ref,\r
+    uint32_t iblock, struct ext4_extent_path **ret_path)\r
+{\r
+    struct ext4_extent_header *eh =\r
+        ext4_inode_get_extent_header(inode_ref->inode);\r
+\r
+    uint16_t depth = ext4_extent_header_get_depth(eh);\r
+    uint16_t i;\r
+    struct ext4_extent_path *tmp_path;\r
+\r
+    /* Added 2 for possible tree growing */\r
+    tmp_path = malloc(sizeof(struct ext4_extent_path) * (depth + 2));\r
+    if (tmp_path == NULL)\r
+        return ENOMEM;\r
+\r
+    /* Initialize structure for algorithm start */\r
+    tmp_path[0].block = inode_ref->block;\r
+    tmp_path[0].header = eh;\r
+\r
+    /* Walk through the extent tree */\r
+    uint16_t pos = 0;\r
+    int rc;\r
+    while (ext4_extent_header_get_depth(eh) != 0) {\r
+        /* Search index in index node by iblock */\r
+        ext4_extent_binsearch_idx(tmp_path[pos].header,\r
+            &tmp_path[pos].index, iblock);\r
+\r
+        tmp_path[pos].depth = depth;\r
+        tmp_path[pos].extent = NULL;\r
+\r
+        ext4_assert(tmp_path[pos].index != 0);\r
+\r
+        /* Load information for the next iteration */\r
+        uint64_t fblock = ext4_extent_index_get_leaf(tmp_path[pos].index);\r
+\r
+        struct ext4_block block;\r
+        rc = ext4_block_get(inode_ref->fs->bdev, &block, fblock);\r
+        if (rc != EOK)\r
+            goto cleanup;\r
+\r
+        pos++;\r
+\r
+        eh = (struct ext4_extent_header *)block.data;\r
+        tmp_path[pos].block = block;\r
+        tmp_path[pos].header = eh;\r
+    }\r
+\r
+    tmp_path[pos].depth = 0;\r
+    tmp_path[pos].extent = NULL;\r
+    tmp_path[pos].index = NULL;\r
+\r
+    /* Find extent in the leaf node */\r
+    ext4_extent_binsearch(tmp_path[pos].header, &tmp_path[pos].extent, iblock);\r
+    *ret_path = tmp_path;\r
+\r
+    return EOK;\r
+\r
+cleanup:\r
+    /*\r
+     * Put loaded blocks\r
+     * From 1: 0 is a block with inode data\r
+     */\r
+    for (i = 1; i < tmp_path->depth; ++i) {\r
+        if (tmp_path[i].block.lb_id)\r
+            ext4_block_set(inode_ref->fs->bdev, &tmp_path[i].block);\r
+    }\r
+\r
+    /* Destroy temporary data structure */\r
+    free(tmp_path);\r
+\r
+    return rc;\r
+}\r
+\r
+/**@brief Release extent and all data blocks covered by the extent.\r
+ * @param inode_ref I-node to release extent and block from\r
+ * @param extent    Extent to release\r
+ * @return Error code */\r
+static int ext4_extent_release(struct ext4_inode_ref *inode_ref,\r
+    struct ext4_extent *extent)\r
+{\r
+    /* Compute number of the first physical block to release */\r
+    uint64_t start = ext4_extent_get_start(extent);\r
+    uint16_t block_count = ext4_extent_get_block_count(extent);\r
+\r
+    return ext4_balloc_free_blocks(inode_ref, start, block_count);\r
+}\r
+\r
+/** Recursively release the whole branch of the extent tree.\r
+ * For each entry of the node release the subbranch and finally release\r
+ * the node. In the leaf node all extents will be released.\r
+ * @param inode_ref I-node where the branch is released\r
+ * @param index     Index in the non-leaf node to be released\r
+ *                  with the whole subtree\r
+ * @return Error code */\r
+static int ext4_extent_release_branch(struct ext4_inode_ref *inode_ref,\r
+        struct ext4_extent_index *index)\r
+{\r
+    uint32_t fblock = ext4_extent_index_get_leaf(index);\r
+    uint32_t i;\r
+    struct ext4_block block;\r
+    int rc = ext4_block_get(inode_ref->fs->bdev, &block, fblock);\r
+    if (rc != EOK)\r
+        return rc;\r
+\r
+    struct ext4_extent_header *header = (void *)block.data;\r
+\r
+    if (ext4_extent_header_get_depth(header)) {\r
+        /* The node is non-leaf, do recursion */\r
+        struct ext4_extent_index *idx = EXT4_EXTENT_FIRST_INDEX(header);\r
+\r
+        /* Release all subbranches */\r
+        for (i = 0; i < ext4_extent_header_get_entries_count(header);\r
+            ++i, ++idx) {\r
+            rc = ext4_extent_release_branch(inode_ref, idx);\r
+            if (rc != EOK)\r
+                return rc;\r
+        }\r
+    } else {\r
+        /* Leaf node reached */\r
+        struct ext4_extent *ext = EXT4_EXTENT_FIRST(header);\r
+\r
+        /* Release all extents and stop recursion */\r
+        for (i = 0; i < ext4_extent_header_get_entries_count(header);\r
+            ++i, ++ext) {\r
+            rc = ext4_extent_release(inode_ref, ext);\r
+            if (rc != EOK)\r
+                return rc;\r
+        }\r
+    }\r
+\r
+    /* Release data block where the node was stored */\r
+\r
+    rc = ext4_block_set(inode_ref->fs->bdev, &block);\r
+    if (rc != EOK)\r
+        return rc;\r
+\r
+    ext4_balloc_free_block(inode_ref, fblock);\r
+\r
+    return EOK;\r
+}\r
+\r
+\r
+int ext4_extent_release_blocks_from(struct ext4_inode_ref *inode_ref,\r
+    uint32_t iblock_from)\r
+{\r
+    /* Find the first extent to modify */\r
+    struct ext4_extent_path *path;\r
+    uint16_t i;\r
+    int rc = ext4_extent_find_extent(inode_ref, iblock_from, &path);\r
+    if (rc != EOK)\r
+        return rc;\r
+\r
+    /* Jump to last item of the path (extent) */\r
+    struct ext4_extent_path *path_ptr = path;\r
+    while (path_ptr->depth != 0)\r
+        path_ptr++;\r
+\r
+    ext4_assert(path_ptr->extent != NULL);\r
+\r
+    /* First extent maybe released partially */\r
+    uint32_t first_iblock =\r
+        ext4_extent_get_first_block(path_ptr->extent);\r
+    uint32_t first_fblock =\r
+        ext4_extent_get_start(path_ptr->extent) + iblock_from - first_iblock;\r
+\r
+    uint16_t block_count = ext4_extent_get_block_count(path_ptr->extent);\r
+\r
+    uint16_t delete_count = block_count -\r
+        (ext4_extent_get_start(path_ptr->extent) - first_fblock);\r
+\r
+    /* Release all blocks */\r
+    rc = ext4_balloc_free_blocks(inode_ref, first_fblock, delete_count);\r
+    if (rc != EOK)\r
+        goto cleanup;\r
+\r
+    /* Correct counter */\r
+    block_count -= delete_count;\r
+    ext4_extent_set_block_count(path_ptr->extent, block_count);\r
+\r
+    /* Initialize the following loop */\r
+    uint16_t entries =\r
+        ext4_extent_header_get_entries_count(path_ptr->header);\r
+    struct ext4_extent *tmp_ext = path_ptr->extent + 1;\r
+    struct ext4_extent *stop_ext = EXT4_EXTENT_FIRST(path_ptr->header) + entries;\r
+\r
+    /* If first extent empty, release it */\r
+    if (block_count == 0)\r
+        entries--;\r
+\r
+    /* Release all successors of the first extent in the same node */\r
+    while (tmp_ext < stop_ext) {\r
+        first_fblock = ext4_extent_get_start(tmp_ext);\r
+        delete_count = ext4_extent_get_block_count(tmp_ext);\r
+\r
+        rc = ext4_balloc_free_blocks(inode_ref, first_fblock, delete_count);\r
+        if (rc != EOK)\r
+            goto cleanup;\r
+\r
+        entries--;\r
+        tmp_ext++;\r
+    }\r
+\r
+    ext4_extent_header_set_entries_count(path_ptr->header, entries);\r
+    path_ptr->block.dirty = true;\r
+\r
+    /* If leaf node is empty, parent entry must be modified */\r
+    bool remove_parent_record = false;\r
+\r
+    /* Don't release root block (including inode data) !!! */\r
+    if ((path_ptr != path) && (entries == 0)) {\r
+        rc = ext4_balloc_free_block(inode_ref, path_ptr->block.lb_id);\r
+        if (rc != EOK)\r
+            goto cleanup;\r
+\r
+        remove_parent_record = true;\r
+    }\r
+\r
+    /* Jump to the parent */\r
+    --path_ptr;\r
+\r
+    /* Release all successors in all tree levels */\r
+    while (path_ptr >= path) {\r
+        entries = ext4_extent_header_get_entries_count(path_ptr->header);\r
+        struct ext4_extent_index *index = path_ptr->index + 1;\r
+        struct ext4_extent_index *stop =\r
+            EXT4_EXTENT_FIRST_INDEX(path_ptr->header) + entries;\r
+\r
+        /* Correct entries count because of changes in the previous iteration */\r
+        if (remove_parent_record)\r
+            entries--;\r
+\r
+        /* Iterate over all entries and release the whole subtrees */\r
+        while (index < stop) {\r
+            rc = ext4_extent_release_branch(inode_ref, index);\r
+            if (rc != EOK)\r
+                goto cleanup;\r
+\r
+            ++index;\r
+            --entries;\r
+        }\r
+\r
+        ext4_extent_header_set_entries_count(path_ptr->header, entries);\r
+        path_ptr->block.dirty = true;\r
+\r
+        /* Free the node if it is empty */\r
+        if ((entries == 0) && (path_ptr != path)) {\r
+            rc = ext4_balloc_free_block(inode_ref, path_ptr->block.lb_id);\r
+            if (rc != EOK)\r
+                goto cleanup;\r
+\r
+            /* Mark parent to be checked */\r
+            remove_parent_record = true;\r
+        } else\r
+            remove_parent_record = false;\r
+\r
+        --path_ptr;\r
+    }\r
+\r
+cleanup:\r
+    /*\r
+     * Put loaded blocks\r
+     * starting from 1: 0 is a block with inode data\r
+     */\r
+    for (i = 1; i <= path->depth; ++i) {\r
+        if (path[i].block.lb_id)\r
+            ext4_block_set(inode_ref->fs->bdev, &path[i].block);\r
+    }\r
+\r
+    /* Destroy temporary data structure */\r
+    free(path);\r
+\r
+    return rc;\r
+}\r
+\r
+/**@brief Append new extent to the i-node and do some splitting if necessary.\r
+ * @param inode_ref      I-node to append extent to\r
+ * @param path           Path in the extent tree for possible splitting\r
+ * @param last_path_item Input/output parameter for pointer to the last\r
+ *                       valid item in the extent tree path\r
+ * @param iblock         Logical index of block to append extent for\r
+ * @return Error code */\r
+static int ext4_extent_append_extent(struct ext4_inode_ref *inode_ref,\r
+    struct ext4_extent_path *path, uint32_t iblock)\r
+{\r
+    struct ext4_extent_path *path_ptr = path + path->depth;\r
+\r
+    uint32_t block_size =\r
+        ext4_sb_get_block_size(&inode_ref->fs->sb);\r
+\r
+    /* Start splitting */\r
+    while (path_ptr > path) {\r
+        uint16_t entries =\r
+            ext4_extent_header_get_entries_count(path_ptr->header);\r
+        uint16_t limit =\r
+            ext4_extent_header_get_max_entries_count(path_ptr->header);\r
+\r
+        if (entries == limit) {\r
+            /* Full node - allocate block for new one */\r
+            uint32_t fblock;\r
+            int rc = ext4_balloc_alloc_block(inode_ref, &fblock);\r
+            if (rc != EOK)\r
+                return rc;\r
+\r
+            struct ext4_block block;\r
+            rc = ext4_block_get(inode_ref->fs->bdev, &block, fblock);\r
+            if (rc != EOK) {\r
+                ext4_balloc_free_block(inode_ref, fblock);\r
+                return rc;\r
+            }\r
+\r
+            /* Put back not modified old block */\r
+            ext4_block_set(inode_ref->fs->bdev, &path_ptr->block);\r
+\r
+            /* Initialize newly allocated block and remember it */\r
+            memset(block.data, 0, block_size);\r
+            path_ptr->block = block;\r
+\r
+            /* Update pointers in extent path structure */\r
+            path_ptr->header = (void *)block.data;\r
+            if (path_ptr->depth) {\r
+                path_ptr->index = EXT4_EXTENT_FIRST_INDEX(path_ptr->header);\r
+                ext4_extent_index_set_first_block(path_ptr->index, iblock);\r
+                ext4_extent_index_set_leaf(path_ptr->index,\r
+                    (path_ptr + 1)->block.lb_id);\r
+                limit = (block_size - sizeof(struct ext4_extent_header)) /\r
+                    sizeof(struct ext4_extent_index);\r
+            } else {\r
+                path_ptr->extent = EXT4_EXTENT_FIRST(path_ptr->header);\r
+                ext4_extent_set_first_block(path_ptr->extent, iblock);\r
+                limit = (block_size - sizeof(struct ext4_extent_header)) /\r
+                    sizeof(struct ext4_extent);\r
+            }\r
+\r
+            /* Initialize on-disk structure (header) */\r
+            ext4_extent_header_set_entries_count(path_ptr->header, 1);\r
+            ext4_extent_header_set_max_entries_count(path_ptr->header, limit);\r
+            ext4_extent_header_set_magic(path_ptr->header, EXT4_EXTENT_MAGIC);\r
+            ext4_extent_header_set_depth(path_ptr->header, path_ptr->depth);\r
+            ext4_extent_header_set_generation(path_ptr->header, 0);\r
+\r
+            path_ptr->block.dirty = true;\r
+\r
+            /* Jump to the preceeding item */\r
+            path_ptr--;\r
+        } else {\r
+            /* Node with free space */\r
+            if (path_ptr->depth) {\r
+                path_ptr->index = EXT4_EXTENT_FIRST_INDEX(path_ptr->header) + entries;\r
+                ext4_extent_index_set_first_block(path_ptr->index, iblock);\r
+                ext4_extent_index_set_leaf(path_ptr->index,\r
+                    (path_ptr + 1)->block.lb_id);\r
+            } else {\r
+                path_ptr->extent = EXT4_EXTENT_FIRST(path_ptr->header) + entries;\r
+                ext4_extent_set_first_block(path_ptr->extent, iblock);\r
+            }\r
+\r
+            ext4_extent_header_set_entries_count(path_ptr->header, entries + 1);\r
+            path_ptr->block.dirty = true;\r
+\r
+            /* No more splitting needed */\r
+            return EOK;\r
+        }\r
+    }\r
+\r
+    ext4_assert(path_ptr == path);\r
+\r
+    /* Should be the root split too? */\r
+\r
+    uint16_t entries = ext4_extent_header_get_entries_count(path->header);\r
+    uint16_t limit = ext4_extent_header_get_max_entries_count(path->header);\r
+\r
+    if (entries == limit) {\r
+        uint32_t new_fblock;\r
+        int rc = ext4_balloc_alloc_block(inode_ref, &new_fblock);\r
+        if (rc != EOK)\r
+            return rc;\r
+\r
+        struct ext4_block block;\r
+        rc = ext4_block_get(inode_ref->fs->bdev, &block, new_fblock);\r
+        if (rc != EOK)\r
+            return rc;\r
+\r
+        /* Initialize newly allocated block */\r
+        memset(block.data, 0, block_size);\r
+\r
+        /* Move data from root to the new block */\r
+        memcpy(block.data, inode_ref->inode->blocks,\r
+            EXT4_INODE_BLOCKS * sizeof(uint32_t));\r
+\r
+        /* Data block is initialized */\r
+\r
+        struct ext4_block *root_block = &path->block;\r
+        uint16_t root_depth = path->depth;\r
+        struct ext4_extent_header *root_header = path->header;\r
+\r
+        /* Make space for tree growing */\r
+        struct ext4_extent_path *new_root = path;\r
+        struct ext4_extent_path *old_root = path + 1;\r
+\r
+        size_t nbytes = sizeof(struct ext4_extent_path) * (path->depth + 1);\r
+        memmove(old_root, new_root, nbytes);\r
+        memset(new_root, 0, sizeof(struct ext4_extent_path));\r
+\r
+        /* Update old root structure */\r
+        old_root->block = block;\r
+        old_root->header = (struct ext4_extent_header *)block.data;\r
+\r
+        /* Add new entry and update limit for entries */\r
+        if (old_root->depth) {\r
+            limit = (block_size - sizeof(struct ext4_extent_header)) /\r
+                sizeof(struct ext4_extent_index);\r
+            old_root->index = EXT4_EXTENT_FIRST_INDEX(old_root->header) + entries;\r
+            ext4_extent_index_set_first_block(old_root->index, iblock);\r
+            ext4_extent_index_set_leaf(old_root->index,\r
+                (old_root + 1)->block.lb_id);\r
+            old_root->extent = NULL;\r
+        } else {\r
+            limit = (block_size - sizeof(struct ext4_extent_header)) /\r
+                sizeof(struct ext4_extent);\r
+            old_root->extent = EXT4_EXTENT_FIRST(old_root->header) + entries;\r
+            ext4_extent_set_first_block(old_root->extent, iblock);\r
+            old_root->index = NULL;\r
+        }\r
+\r
+        ext4_extent_header_set_entries_count(old_root->header, entries + 1);\r
+        ext4_extent_header_set_max_entries_count(old_root->header, limit);\r
+\r
+        old_root->block.dirty = true;\r
+\r
+        /* Re-initialize new root metadata */\r
+        new_root->depth = root_depth + 1;\r
+        new_root->block = *root_block;\r
+        new_root->header = root_header;\r
+        new_root->extent = NULL;\r
+        new_root->index = EXT4_EXTENT_FIRST_INDEX(new_root->header);\r
+\r
+        ext4_extent_header_set_depth(new_root->header, new_root->depth);\r
+\r
+        /* Create new entry in root */\r
+        ext4_extent_header_set_entries_count(new_root->header, 1);\r
+        ext4_extent_index_set_first_block(new_root->index, 0);\r
+        ext4_extent_index_set_leaf(new_root->index, new_fblock);\r
+\r
+        new_root->block.dirty = true;\r
+    } else {\r
+        if (path->depth) {\r
+            path->index = EXT4_EXTENT_FIRST_INDEX(path->header) + entries;\r
+            ext4_extent_index_set_first_block(path->index, iblock);\r
+            ext4_extent_index_set_leaf(path->index, (path + 1)->block.lb_id);\r
+        } else {\r
+            path->extent = EXT4_EXTENT_FIRST(path->header) + entries;\r
+            ext4_extent_set_first_block(path->extent, iblock);\r
+        }\r
+\r
+        ext4_extent_header_set_entries_count(path->header, entries + 1);\r
+        path->block.dirty = true;\r
+    }\r
+\r
+    return EOK;\r
+}\r
+\r
+\r
+int ext4_extent_append_block(struct ext4_inode_ref *inode_ref,\r
+        uint32_t *iblock, uint32_t *fblock, bool update_size)\r
+{\r
+    uint16_t i;\r
+    struct ext4_sblock *sb = &inode_ref->fs->sb;\r
+    uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode);\r
+    uint32_t block_size = ext4_sb_get_block_size(sb);\r
+\r
+    /* Calculate number of new logical block */\r
+    uint32_t new_block_idx = 0;\r
+    if (inode_size > 0) {\r
+        if ((inode_size % block_size) != 0)\r
+            inode_size += block_size - (inode_size % block_size);\r
+\r
+        new_block_idx = inode_size / block_size;\r
+    }\r
+\r
+    /* Load the nearest leaf (with extent) */\r
+    struct ext4_extent_path *path;\r
+    int rc = ext4_extent_find_extent(inode_ref, new_block_idx, &path);\r
+    if (rc != EOK)\r
+        return rc;\r
+\r
+    /* Jump to last item of the path (extent) */\r
+    struct ext4_extent_path *path_ptr = path;\r
+    while (path_ptr->depth != 0)\r
+        path_ptr++;\r
+\r
+    /* Add new extent to the node if not present */\r
+    if (path_ptr->extent == NULL)\r
+        goto append_extent;\r
+\r
+    uint16_t block_count = ext4_extent_get_block_count(path_ptr->extent);\r
+    uint16_t block_limit = (1 << 15);\r
+\r
+    uint32_t phys_block = 0;\r
+    if (block_count < block_limit) {\r
+        /* There is space for new block in the extent */\r
+        if (block_count == 0) {\r
+            /* Existing extent is empty */\r
+            rc = ext4_balloc_alloc_block(inode_ref, &phys_block);\r
+            if (rc != EOK)\r
+                goto finish;\r
+\r
+            /* Initialize extent */\r
+            ext4_extent_set_first_block(path_ptr->extent, new_block_idx);\r
+            ext4_extent_set_start(path_ptr->extent, phys_block);\r
+            ext4_extent_set_block_count(path_ptr->extent, 1);\r
+\r
+            /* Update i-node */\r
+            if (update_size) {\r
+                ext4_inode_set_size(inode_ref->inode, inode_size + block_size);\r
+                inode_ref->dirty = true;\r
+            }\r
+\r
+            path_ptr->block.dirty = true;\r
+\r
+            goto finish;\r
+        } else {\r
+            /* Existing extent contains some blocks */\r
+            phys_block = ext4_extent_get_start(path_ptr->extent);\r
+            phys_block += ext4_extent_get_block_count(path_ptr->extent);\r
+\r
+            /* Check if the following block is free for allocation */\r
+            bool free;\r
+            rc = ext4_balloc_try_alloc_block(inode_ref, phys_block, &free);\r
+            if (rc != EOK)\r
+                goto finish;\r
+\r
+            if (!free) {\r
+                /* Target is not free, new block must be appended to new extent */\r
+                goto append_extent;\r
+            }\r
+\r
+            /* Update extent */\r
+            ext4_extent_set_block_count(path_ptr->extent, block_count + 1);\r
+\r
+            /* Update i-node */\r
+            if (update_size) {\r
+                ext4_inode_set_size(inode_ref->inode, inode_size + block_size);\r
+                inode_ref->dirty = true;\r
+            }\r
+\r
+            path_ptr->block.dirty = true;\r
+\r
+            goto finish;\r
+        }\r
+    }\r
+\r
+\r
+append_extent:\r
+    /* Append new extent to the tree */\r
+    phys_block = 0;\r
+\r
+    /* Allocate new data block */\r
+    rc = ext4_balloc_alloc_block(inode_ref, &phys_block);\r
+    if (rc != EOK)\r
+        goto finish;\r
+\r
+    /* Append extent for new block (includes tree splitting if needed) */\r
+    rc = ext4_extent_append_extent(inode_ref, path, new_block_idx);\r
+    if (rc != EOK) {\r
+        ext4_balloc_free_block(inode_ref, phys_block);\r
+        goto finish;\r
+    }\r
+\r
+    uint32_t tree_depth = ext4_extent_header_get_depth(path->header);\r
+    path_ptr = path + tree_depth;\r
+\r
+    /* Initialize newly created extent */\r
+    ext4_extent_set_block_count(path_ptr->extent, 1);\r
+    ext4_extent_set_first_block(path_ptr->extent, new_block_idx);\r
+    ext4_extent_set_start(path_ptr->extent, phys_block);\r
+\r
+    /* Update i-node */\r
+    if (update_size) {\r
+        ext4_inode_set_size(inode_ref->inode, inode_size + block_size);\r
+        inode_ref->dirty = true;\r
+    }\r
+\r
+    path_ptr->block.dirty = true;\r
+\r
+finish:\r
+    /* Set return values */\r
+    *iblock = new_block_idx;\r
+    *fblock = phys_block;\r
+\r
+    /*\r
+     * Put loaded blocks\r
+     * starting from 1: 0 is a block with inode data\r
+     */\r
+    for (i = 1; i <= path->depth; ++i) {\r
+        if (path[i].block.lb_id)\r
+            ext4_block_set(inode_ref->fs->bdev, &path[i].block);\r
+    }\r
+\r
+    /* Destroy temporary data structure */\r
+    free(path);\r
+\r
+    return rc;\r
+}\r
+\r
+/**\r
+ * @}\r
+ */\r
diff --git a/lwext4/ext4_extent.h b/lwext4/ext4_extent.h
new file mode 100644 (file)
index 0000000..86d3059
--- /dev/null
@@ -0,0 +1,189 @@
+/*\r
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)\r
+ *\r
+ *\r
+ * HelenOS:\r
+ * Copyright (c) 2012 Martin Sucha\r
+ * Copyright (c) 2012 Frantisek Princ\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions\r
+ * are met:\r
+ *\r
+ * - Redistributions of source code must retain the above copyright\r
+ *   notice, this list of conditions and the following disclaimer.\r
+ * - Redistributions in binary form must reproduce the above copyright\r
+ *   notice, this list of conditions and the following disclaimer in the\r
+ *   documentation and/or other materials provided with the distribution.\r
+ * - The name of the author may not be used to endorse or promote products\r
+ *   derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+\r
+/** @addtogroup lwext4\r
+ * @{\r
+ */\r
+/**\r
+ * @file  ext4_extent.h\r
+ * @brief More complex filesystem functions.\r
+ */\r
+#ifndef EXT4_EXTENT_H_\r
+#define EXT4_EXTENT_H_\r
+\r
+#include <ext4_config.h>\r
+#include <ext4_types.h>\r
+\r
+/**@brief Get logical number of the block covered by extent.\r
+ * @param extent Extent to load number from\r
+ * @return Logical number of the first block covered by extent */\r
+uint32_t ext4_extent_get_first_block(struct ext4_extent *extent);\r
+\r
+/**@brief Set logical number of the first block covered by extent.\r
+ * @param extent Extent to set number to\r
+ * @param iblock Logical number of the first block covered by extent */\r
+void ext4_extent_set_first_block(struct ext4_extent *extent, uint32_t iblock);\r
+\r
+/**@brief Get number of blocks covered by extent.\r
+ * @param extent Extent to load count from\r
+ * @return Number of blocks covered by extent */\r
+uint16_t ext4_extent_get_block_count(struct ext4_extent *extent);\r
+\r
+/**@brief Set number of blocks covered by extent.\r
+ * @param extent Extent to load count from\r
+ * @param count  Number of blocks covered by extent */\r
+void ext4_extent_set_block_count(struct ext4_extent *extent, uint16_t count);\r
+\r
+/**@brief Get physical number of the first block covered by extent.\r
+ * @param extent Extent to load number\r
+ * @return Physical number of the first block covered by extent */\r
+uint64_t ext4_extent_get_start(struct ext4_extent *extent);\r
+\r
+/**@brief Set physical number of the first block covered by extent.\r
+ * @param extent Extent to load number\r
+ * @param fblock Physical number of the first block covered by extent */\r
+void ext4_extent_set_start(struct ext4_extent *extent, uint64_t fblock);\r
+\r
+\r
+/**@brief Get logical number of the block covered by extent index.\r
+ * @param index Extent index to load number from\r
+ * @return Logical number of the first block covered by extent index */\r
+uint32_t ext4_extent_index_get_first_block(struct ext4_extent_index *index);\r
+\r
+/**@brief Set logical number of the block covered by extent index.\r
+ * @param index  Extent index to set number to\r
+ * @param iblock Logical number of the first block covered by extent index */\r
+void ext4_extent_index_set_first_block(struct ext4_extent_index *index,\r
+    uint32_t iblock);\r
+\r
+/**@brief Get physical number of block where the child node is located.\r
+ * @param index Extent index to load number from\r
+ * @return Physical number of the block with child node */\r
+uint64_t ext4_extent_index_get_leaf(struct ext4_extent_index *index);\r
+\r
+\r
+/**@brief Set physical number of block where the child node is located.\r
+ * @param index  Extent index to set number to\r
+ * @param fblock Ohysical number of the block with child node */\r
+void ext4_extent_index_set_leaf(struct ext4_extent_index *index,\r
+    uint64_t fblock);\r
+\r
+\r
+/**@brief Get magic value from extent header.\r
+ * @param header Extent header to load value from\r
+ * @return Magic value of extent header */\r
+uint16_t ext4_extent_header_get_magic(struct ext4_extent_header *header);\r
+\r
+/**@brief Set magic value to extent header.\r
+ * @param header Extent header to set value to\r
+ * @param magic  Magic value of extent header */\r
+void ext4_extent_header_set_magic(struct ext4_extent_header *header,\r
+    uint16_t magic);\r
+\r
+/**@brief Get number of entries from extent header\r
+ * @param header Extent header to get value from\r
+ * @return Number of entries covered by extent header */\r
+uint16_t ext4_extent_header_get_entries_count(struct ext4_extent_header *header);\r
+\r
+/**@brief Set number of entries to extent header\r
+ * @param header Extent header to set value to\r
+ * @param count  Number of entries covered by extent header */\r
+void ext4_extent_header_set_entries_count(struct ext4_extent_header *header,\r
+    uint16_t count);\r
+\r
+/**@brief Get maximum number of entries from extent header\r
+ * @param header Extent header to get value from\r
+ * @return Maximum number of entries covered by extent header */\r
+uint16_t ext4_extent_header_get_max_entries_count(struct ext4_extent_header *header);\r
+\r
+/**@brief Set maximum number of entries to extent header\r
+ * @param header    Extent header to set value to\r
+ * @param max_count Maximum number of entries covered by extent header */\r
+void ext4_extent_header_set_max_entries_count(struct ext4_extent_header *header,\r
+    uint16_t max_count);\r
+\r
+/**@brief Get depth of extent subtree.\r
+ * @param header Extent header to get value from\r
+ * @return Depth of extent subtree */\r
+uint16_t ext4_extent_header_get_depth(struct ext4_extent_header *header);\r
+\r
+/**@brief Set depth of extent subtree.\r
+ * @param header Extent header to set value to\r
+ * @param depth  Depth of extent subtree */\r
+void ext4_extent_header_set_depth(struct ext4_extent_header *header,\r
+    uint16_t depth);\r
+\r
+/**@brief Get generation from extent header\r
+ * @param header Extent header to get value from\r
+ * @return Generation */\r
+uint32_t ext4_extent_header_get_generation(struct ext4_extent_header *header);\r
+\r
+/**@brief Set generation to extent header\r
+ * @param header     Extent header to set value to\r
+ * @param generation Generation */\r
+void ext4_extent_header_set_generation(struct ext4_extent_header *header,\r
+    uint32_t generation);\r
+\r
+/**@brief Find physical block in the extent tree by logical block number.\r
+ * There is no need to save path in the tree during this algorithm.\r
+ * @param inode_ref I-node to load block from\r
+ * @param iblock    Logical block number to find\r
+ * @param fblock    Output value for physical block number\r
+ * @return Error code*/\r
+int ext4_extent_find_block(struct ext4_inode_ref *inode_ref, uint32_t iblock,\r
+    uint32_t *fblock);\r
+\r
+/**@brief Release all data blocks starting from specified logical block.\r
+ * @param inode_ref   I-node to release blocks from\r
+ * @param iblock_from First logical block to release\r
+ * @return Error code */\r
+int ext4_extent_release_blocks_from(struct ext4_inode_ref *inode_ref,\r
+    uint32_t iblock_from);\r
+\r
+/**@brief Append data block to the i-node.\r
+ * This function allocates data block, tries to append it\r
+ * to some existing extent or creates new extents.\r
+ * It includes possible extent tree modifications (splitting).\r
+ * @param inode_ref I-node to append block to\r
+ * @param iblock    Output logical number of newly allocated block\r
+ * @param fblock    Output physical block address of newly allocated block\r
+ *\r
+ * @return Error code*/\r
+int ext4_extent_append_block(struct ext4_inode_ref *inode_ref,\r
+        uint32_t *iblock, uint32_t *fblock, bool update_size);\r
+\r
+\r
+#endif /* EXT4_EXTENT_H_ */\r
+/**\r
+ * @}\r
+ */\r
index 1516f6ad32380b23d9fec089a454d6d9ecace7f1..c06f43dc8eb0e0a7c09e3a8a7efb3fd2df922fa3 100644 (file)
@@ -50,6 +50,7 @@
 #include <ext4_bitmap.h>
 #include <ext4_inode.h>
 #include <ext4_ialloc.h>
+#include <ext4_extent.h>
 #include <string.h>
 
 int ext4_fs_init(struct ext4_fs *fs, struct ext4_blockdev *bdev)
@@ -125,24 +126,184 @@ int ext4_fs_fini(struct ext4_fs *fs)
     return ext4_sb_write(fs->bdev, &fs->sb);
 }
 
+static void ext4_fs_debug_features_incomp(uint32_t features_incompatible)
+{
+
+    if(features_incompatible &
+            EXT4_FEATURE_INCOMPAT_COMPRESSION){
+        ext4_dprintf(EXT4_DEBUG_FS,
+                "EXT4_FEATURE_INCOMPAT_COMPRESSION\n");
+    }
+    if(features_incompatible &
+            EXT4_FEATURE_INCOMPAT_FILETYPE){
+        ext4_dprintf(EXT4_DEBUG_FS,
+                "EXT4_FEATURE_INCOMPAT_FILETYPE\n");
+    }
+    if(features_incompatible &
+            EXT4_FEATURE_INCOMPAT_RECOVER){
+        ext4_dprintf(EXT4_DEBUG_FS,
+                "EXT4_FEATURE_INCOMPAT_RECOVER\n");
+    }
+    if(features_incompatible &
+            EXT4_FEATURE_INCOMPAT_JOURNAL_DEV){
+        ext4_dprintf(EXT4_DEBUG_FS,
+                "EXT4_FEATURE_INCOMPAT_JOURNAL_DEV\n");
+    }
+    if(features_incompatible &
+            EXT4_FEATURE_INCOMPAT_META_BG){
+        ext4_dprintf(EXT4_DEBUG_FS,
+                "EXT4_FEATURE_INCOMPAT_META_BG\n");
+    }
+    if(features_incompatible &
+            EXT4_FEATURE_INCOMPAT_EXTENTS){
+        ext4_dprintf(EXT4_DEBUG_FS,
+                "EXT4_FEATURE_INCOMPAT_EXTENTS\n");
+    }
+    if(features_incompatible &
+            EXT4_FEATURE_INCOMPAT_64BIT){
+        ext4_dprintf(EXT4_DEBUG_FS,
+                "EXT4_FEATURE_INCOMPAT_64BIT\n");
+    }
+    if(features_incompatible &
+            EXT4_FEATURE_INCOMPAT_MMP){
+        ext4_dprintf(EXT4_DEBUG_FS,
+                "EXT4_FEATURE_INCOMPAT_MMP\n");
+    }
+    if(features_incompatible &
+            EXT4_FEATURE_INCOMPAT_FLEX_BG){
+        ext4_dprintf(EXT4_DEBUG_FS,
+                "EXT4_FEATURE_INCOMPAT_FLEX_BG\n");
+    }
+    if(features_incompatible &
+            EXT4_FEATURE_INCOMPAT_EA_INODE){
+        ext4_dprintf(EXT4_DEBUG_FS,
+                "EXT4_FEATURE_INCOMPAT_EA_INODE\n");
+    }
+    if(features_incompatible &
+            EXT4_FEATURE_INCOMPAT_DIRDATA){
+        ext4_dprintf(EXT4_DEBUG_FS,
+                "EXT4_FEATURE_INCOMPAT_DIRDATA\n");
+    }
+}
+static void ext4_fs_debug_features_comp(uint32_t features_compatible)
+{
+    if(features_compatible &
+            EXT4_FEATURE_COMPAT_DIR_PREALLOC){
+        ext4_dprintf(EXT4_DEBUG_FS,
+                "EXT4_FEATURE_COMPAT_DIR_PREALLOC\n");
+    }
+    if(features_compatible &
+            EXT4_FEATURE_COMPAT_IMAGIC_INODES){
+        ext4_dprintf(EXT4_DEBUG_FS,
+                "EXT4_FEATURE_COMPAT_IMAGIC_INODES\n");
+    }
+    if(features_compatible &
+            EXT4_FEATURE_COMPAT_HAS_JOURNAL){
+        ext4_dprintf(EXT4_DEBUG_FS,
+                "EXT4_FEATURE_COMPAT_HAS_JOURNAL\n");
+    }
+    if(features_compatible &
+            EXT4_FEATURE_COMPAT_EXT_ATTR){
+        ext4_dprintf(EXT4_DEBUG_FS,
+                "EXT4_FEATURE_COMPAT_EXT_ATTR\n");
+    }
+    if(features_compatible &
+            EXT4_FEATURE_COMPAT_RESIZE_INODE){
+        ext4_dprintf(EXT4_DEBUG_FS,
+                "EXT4_FEATURE_COMPAT_RESIZE_INODE\n");
+    }
+    if(features_compatible &
+            EXT4_FEATURE_COMPAT_DIR_INDEX){
+        ext4_dprintf(EXT4_DEBUG_FS,
+                "EXT4_FEATURE_COMPAT_DIR_INDEX\n");
+    }
+}
+
+static void ext4_fs_debug_features_ro(uint32_t features_ro)
+{
+    if(features_ro &
+            EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER){
+        ext4_dprintf(EXT4_DEBUG_FS,
+                "EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER\n");
+    }
+    if(features_ro &
+            EXT4_FEATURE_RO_COMPAT_LARGE_FILE){
+        ext4_dprintf(EXT4_DEBUG_FS,
+                "EXT4_FEATURE_RO_COMPAT_LARGE_FILE\n");
+    }
+    if(features_ro &
+            EXT4_FEATURE_RO_COMPAT_BTREE_DIR){
+        ext4_dprintf(EXT4_DEBUG_FS,
+                "EXT4_FEATURE_RO_COMPAT_BTREE_DIR\n");
+    }
+    if(features_ro &
+            EXT4_FEATURE_RO_COMPAT_HUGE_FILE){
+        ext4_dprintf(EXT4_DEBUG_FS,
+                "EXT4_FEATURE_RO_COMPAT_HUGE_FILE\n");
+    }
+    if(features_ro &
+            EXT4_FEATURE_RO_COMPAT_GDT_CSUM){
+        ext4_dprintf(EXT4_DEBUG_FS,
+                "EXT4_FEATURE_RO_COMPAT_GDT_CSUM\n");
+    }
+    if(features_ro &
+            EXT4_FEATURE_RO_COMPAT_DIR_NLINK){
+        ext4_dprintf(EXT4_DEBUG_FS,
+                "EXT4_FEATURE_RO_COMPAT_DIR_NLINK\n");
+    }
+    if(features_ro &
+            EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE){
+        ext4_dprintf(EXT4_DEBUG_FS,
+                "EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE\n");
+    }
+}
+
 int ext4_fs_check_features(struct ext4_fs *fs, bool *read_only)
 {
     ext4_assert(fs && read_only);
-
+    uint32_t v;
     if(ext4_get32(&fs->sb, rev_level) == 0){
         *read_only = false;
         return EOK;
     }
+    ext4_dprintf(EXT4_DEBUG_FS,
+        "\nSblock rev_level: \n%d\n", ext4_get32(&fs->sb, rev_level) );
+
+    ext4_dprintf(EXT4_DEBUG_FS,
+        "\nSblock minor_rev_level: \n%d\n",
+        ext4_get32(&fs->sb, minor_rev_level));
+
+    ext4_dprintf(EXT4_DEBUG_FS,
+        "\nSblock features_incompatible:\n");
+    ext4_fs_debug_features_incomp(ext4_get32(&fs->sb, features_incompatible));
+
+    ext4_dprintf(EXT4_DEBUG_FS,
+        "\nSblock features_compatible:\n");
+    ext4_fs_debug_features_comp(ext4_get32(&fs->sb, features_compatible));
+
+    ext4_dprintf(EXT4_DEBUG_FS,
+        "\nSblock features_read_only:\n");
+    ext4_fs_debug_features_ro(ext4_get32(&fs->sb, features_read_only));
 
     /*Check features_incompatible*/
-    if ((ext4_get32(&fs->sb, features_incompatible) &
-            (~EXT4_FEATURE_INCOMPAT_SUPP)) )
+    v = (ext4_get32(&fs->sb, features_incompatible) &
+            (~EXT4_FEATURE_INCOMPAT_SUPP));
+    if (v){
+        ext4_dprintf(EXT4_DEBUG_FS,
+                "\nERROR sblock features_incompatible. Unsupported:\n");
+        ext4_fs_debug_features_incomp(v);
         return ENOTSUP;
+    }
 
 
     /*Check features_read_only*/
-    if ((ext4_get32(&fs->sb, features_read_only) &
-            (~EXT4_FEATURE_RO_COMPAT_SUPP))){
+    v = (ext4_get32(&fs->sb, features_read_only) &
+            (~EXT4_FEATURE_RO_COMPAT_SUPP));
+    if (v){
+        ext4_dprintf(EXT4_DEBUG_FS,
+                "\nERROR sblock features_read_only . Unsupported:\n");
+        ext4_fs_debug_features_incomp(v);
+
         *read_only = true;
         return EOK;
     }
@@ -554,14 +715,14 @@ int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref,
 
 
         /* Initialize extent root header */
-        ext4_extent_header_t *header = ext4_inode_get_extent_header(inode);
+        struct ext4_extent_header *header = ext4_inode_get_extent_header(inode);
         ext4_extent_header_set_depth(header, 0);
         ext4_extent_header_set_entries_count(header, 0);
         ext4_extent_header_set_generation(header, 0);
         ext4_extent_header_set_magic(header, EXT4_EXTENT_MAGIC);
 
         uint16_t max_entries = (EXT4_INODE_BLOCKS * sizeof(uint32_t) -
-                sizeof(ext4_extent_header_t)) / sizeof(ext4_extent_t);
+                sizeof(struct ext4_extent_header)) / sizeof(struct ext4_extent);
 
         ext4_extent_header_set_max_entries_count(header, max_entries);
     }
index d359e9941f788008bf5374a22d25b917006ee92e..1097d6b902635ea2dd1f6ee3105bb670c21c9e8b 100644 (file)
@@ -180,7 +180,7 @@ uint64_t ext4_inode_get_blocks_count(struct ext4_sblock *sb,
             EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {\r
 \r
         /* 48-bit field */\r
-        count = ((uint64_t) to_le16(inode->osd2.linux2.blocks_high)) << 32;\r
+        count |= ((uint64_t) to_le16(inode->osd2.linux2.blocks_high)) << 32;\r
 \r
         if (ext4_inode_has_flag(inode, EXT4_INODE_FLAG_HUGE_FILE)) {\r
 \r