Add extra config options
[lwext4.git] / lwext4 / ext4_fs.c
index 7bfd3e65112fad0f617165159578f1419945208b..5edfda550619e36ce62ba2e33b3436512a41898f 100644 (file)
@@ -131,91 +131,86 @@ 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");
+        ext4_dprintf(EXT4_DEBUG_FS, "compression\n");
     }
     if(features_incompatible &
             EXT4_FEATURE_INCOMPAT_FILETYPE){
-        ext4_dprintf(EXT4_DEBUG_FS,
-                "EXT4_FEATURE_INCOMPAT_FILETYPE\n");
+        ext4_dprintf(EXT4_DEBUG_FS, "filetype\n");
     }
     if(features_incompatible &
             EXT4_FEATURE_INCOMPAT_RECOVER){
-        ext4_dprintf(EXT4_DEBUG_FS,
-                "EXT4_FEATURE_INCOMPAT_RECOVER\n");
+        ext4_dprintf(EXT4_DEBUG_FS, "recover\n");
     }
     if(features_incompatible &
             EXT4_FEATURE_INCOMPAT_JOURNAL_DEV){
-        ext4_dprintf(EXT4_DEBUG_FS,
-                "EXT4_FEATURE_INCOMPAT_JOURNAL_DEV\n");
+        ext4_dprintf(EXT4_DEBUG_FS,"journal_dev\n");
     }
     if(features_incompatible &
             EXT4_FEATURE_INCOMPAT_META_BG){
-        ext4_dprintf(EXT4_DEBUG_FS,
-                "EXT4_FEATURE_INCOMPAT_META_BG\n");
+        ext4_dprintf(EXT4_DEBUG_FS, "meta_bg\n");
     }
     if(features_incompatible &
             EXT4_FEATURE_INCOMPAT_EXTENTS){
-        ext4_dprintf(EXT4_DEBUG_FS,
-                "EXT4_FEATURE_INCOMPAT_EXTENTS\n");
+        ext4_dprintf(EXT4_DEBUG_FS, "extents\n");
     }
     if(features_incompatible &
             EXT4_FEATURE_INCOMPAT_64BIT){
-        ext4_dprintf(EXT4_DEBUG_FS,
-                "EXT4_FEATURE_INCOMPAT_64BIT\n");
+        ext4_dprintf(EXT4_DEBUG_FS, "64bit\n");
     }
     if(features_incompatible &
             EXT4_FEATURE_INCOMPAT_MMP){
-        ext4_dprintf(EXT4_DEBUG_FS,
-                "EXT4_FEATURE_INCOMPAT_MMP\n");
+        ext4_dprintf(EXT4_DEBUG_FS, "mnp\n");
     }
     if(features_incompatible &
             EXT4_FEATURE_INCOMPAT_FLEX_BG){
-        ext4_dprintf(EXT4_DEBUG_FS,
-                "EXT4_FEATURE_INCOMPAT_FLEX_BG\n");
+        ext4_dprintf(EXT4_DEBUG_FS, "flex_bg\n");
     }
     if(features_incompatible &
             EXT4_FEATURE_INCOMPAT_EA_INODE){
-        ext4_dprintf(EXT4_DEBUG_FS,
-                "EXT4_FEATURE_INCOMPAT_EA_INODE\n");
+        ext4_dprintf(EXT4_DEBUG_FS, "ea_inode\n");
     }
     if(features_incompatible &
             EXT4_FEATURE_INCOMPAT_DIRDATA){
-        ext4_dprintf(EXT4_DEBUG_FS,
-                "EXT4_FEATURE_INCOMPAT_DIRDATA\n");
+        ext4_dprintf(EXT4_DEBUG_FS, "dirdata\n");
+    }
+    if(features_incompatible &
+            EXT4_FEATURE_INCOMPAT_BG_USE_META_CSUM){
+        ext4_dprintf(EXT4_DEBUG_FS, "meta_csum\n");
+    }
+    if(features_incompatible &
+            EXT4_FEATURE_INCOMPAT_LARGEDIR){
+        ext4_dprintf(EXT4_DEBUG_FS, "largedir\n");
+    }
+    if(features_incompatible &
+            EXT4_FEATURE_INCOMPAT_INLINE_DATA){
+        ext4_dprintf(EXT4_DEBUG_FS, "inline_data\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");
+        ext4_dprintf(EXT4_DEBUG_FS, " dir_prealloc\n");
     }
     if(features_compatible &
             EXT4_FEATURE_COMPAT_IMAGIC_INODES){
-        ext4_dprintf(EXT4_DEBUG_FS,
-                "EXT4_FEATURE_COMPAT_IMAGIC_INODES\n");
+        ext4_dprintf(EXT4_DEBUG_FS, "imagic_inodes\n");
     }
     if(features_compatible &
             EXT4_FEATURE_COMPAT_HAS_JOURNAL){
-        ext4_dprintf(EXT4_DEBUG_FS,
-                "EXT4_FEATURE_COMPAT_HAS_JOURNAL\n");
+        ext4_dprintf(EXT4_DEBUG_FS, "has_journal\n");
     }
     if(features_compatible &
             EXT4_FEATURE_COMPAT_EXT_ATTR){
-        ext4_dprintf(EXT4_DEBUG_FS,
-                "EXT4_FEATURE_COMPAT_EXT_ATTR\n");
+        ext4_dprintf(EXT4_DEBUG_FS, "ext_attr\n");
     }
     if(features_compatible &
             EXT4_FEATURE_COMPAT_RESIZE_INODE){
-        ext4_dprintf(EXT4_DEBUG_FS,
-                "EXT4_FEATURE_COMPAT_RESIZE_INODE\n");
+        ext4_dprintf(EXT4_DEBUG_FS, "resize_inode\n");
     }
     if(features_compatible &
             EXT4_FEATURE_COMPAT_DIR_INDEX){
-        ext4_dprintf(EXT4_DEBUG_FS,
-                "EXT4_FEATURE_COMPAT_DIR_INDEX\n");
+        ext4_dprintf(EXT4_DEBUG_FS, "dir_index\n");
     }
 }
 
@@ -223,38 +218,43 @@ 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");
+        ext4_dprintf(EXT4_DEBUG_FS, "sparse_super\n");
     }
     if(features_ro &
             EXT4_FEATURE_RO_COMPAT_LARGE_FILE){
-        ext4_dprintf(EXT4_DEBUG_FS,
-                "EXT4_FEATURE_RO_COMPAT_LARGE_FILE\n");
+        ext4_dprintf(EXT4_DEBUG_FS, "large_file\n");
     }
     if(features_ro &
             EXT4_FEATURE_RO_COMPAT_BTREE_DIR){
-        ext4_dprintf(EXT4_DEBUG_FS,
-                "EXT4_FEATURE_RO_COMPAT_BTREE_DIR\n");
+        ext4_dprintf(EXT4_DEBUG_FS, "btree_dir\n");
     }
     if(features_ro &
             EXT4_FEATURE_RO_COMPAT_HUGE_FILE){
-        ext4_dprintf(EXT4_DEBUG_FS,
-                "EXT4_FEATURE_RO_COMPAT_HUGE_FILE\n");
+        ext4_dprintf(EXT4_DEBUG_FS, "huge_file\n");
     }
     if(features_ro &
             EXT4_FEATURE_RO_COMPAT_GDT_CSUM){
-        ext4_dprintf(EXT4_DEBUG_FS,
-                "EXT4_FEATURE_RO_COMPAT_GDT_CSUM\n");
+        ext4_dprintf(EXT4_DEBUG_FS, "gtd_csum\n");
     }
     if(features_ro &
             EXT4_FEATURE_RO_COMPAT_DIR_NLINK){
-        ext4_dprintf(EXT4_DEBUG_FS,
-                "EXT4_FEATURE_RO_COMPAT_DIR_NLINK\n");
+        ext4_dprintf(EXT4_DEBUG_FS, "dir_nlink\n");
     }
     if(features_ro &
             EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE){
-        ext4_dprintf(EXT4_DEBUG_FS,
-                "EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE\n");
+        ext4_dprintf(EXT4_DEBUG_FS, "extra_isize\n");
+    }
+    if(features_ro &
+            EXT4_FEATURE_RO_COMPAT_QUOTA){
+        ext4_dprintf(EXT4_DEBUG_FS, "quota\n");
+    }
+    if(features_ro &
+            EXT4_FEATURE_RO_COMPAT_BIGALLOC){
+        ext4_dprintf(EXT4_DEBUG_FS, "bigalloc\n");
+    }
+    if(features_ro &
+            EXT4_FEATURE_RO_COMPAT_METADATA_CSUM){
+        ext4_dprintf(EXT4_DEBUG_FS, "metadata_csum\n");
     }
 }
 
@@ -287,7 +287,7 @@ int ext4_fs_check_features(struct ext4_fs *fs, bool *read_only)
 
     /*Check features_incompatible*/
     v = (ext4_get32(&fs->sb, features_incompatible) &
-            (~EXT4_FEATURE_INCOMPAT_SUPP));
+            (~CONFIG_FEATURE_INCOMPAT_SUPP));
     if (v){
         ext4_dprintf(EXT4_DEBUG_FS,
                 "\nERROR sblock features_incompatible. Unsupported:\n");
@@ -298,7 +298,7 @@ int ext4_fs_check_features(struct ext4_fs *fs, bool *read_only)
 
     /*Check features_read_only*/
     v = (ext4_get32(&fs->sb, features_read_only) &
-            (~EXT4_FEATURE_RO_COMPAT_SUPP));
+            (~CONFIG_FEATURE_RO_COMPAT_SUPP));
     if (v){
         ext4_dprintf(EXT4_DEBUG_FS,
                 "\nERROR sblock features_read_only . Unsupported:\n");
@@ -307,35 +307,16 @@ int ext4_fs_check_features(struct ext4_fs *fs, bool *read_only)
         *read_only = true;
         return EOK;
     }
-
     *read_only = false;
 
     return EOK;
 }
 
-uint32_t ext4_fs_baddr2_index_in_group(struct ext4_sblock *s, uint32_t baddr)
-{
-    ext4_assert(baddr);
-    if(ext4_get32(s, first_data_block))
-        baddr--;
-
-    return  baddr % ext4_get32(s, blocks_per_group);
-}
-
-
-
-uint32_t ext4_fs_index_in_group2_baddr(struct ext4_sblock *s, uint32_t index,
-    uint32_t bgid)
-{
-    if(ext4_get32(s, first_data_block))
-        index++;
-
-    return ext4_get32(s, blocks_per_group) * bgid + index;
-}
-
-
-
 
+/**@brief Initialize block bitmap in block group.
+ * @param bg_ref Reference to block group
+ * @return Error code
+ */
 static int ext4_fs_init_block_bitmap(struct ext4_block_group_ref *bg_ref)
 {
     uint32_t i;
@@ -371,6 +352,10 @@ static int ext4_fs_init_block_bitmap(struct ext4_block_group_ref *bg_ref)
     return ext4_block_set(bg_ref->fs->bdev, &block_bitmap);
 }
 
+/**@brief Initialize i-node bitmap in block group.
+ * @param bg_ref Reference to block group
+ * @return Error code
+ */
 static int ext4_fs_init_inode_bitmap(struct ext4_block_group_ref *bg_ref)
 {
     /* Load bitmap */
@@ -405,12 +390,16 @@ static int ext4_fs_init_inode_bitmap(struct ext4_block_group_ref *bg_ref)
     return ext4_block_set(bg_ref->fs->bdev, &block_bitmap);
 }
 
+/**@brief Initialize i-node table in block group.
+ * @param bg_ref Reference to block group
+ * @return Error code
+ */
 static int ext4_fs_init_inode_table(struct ext4_block_group_ref *bg_ref)
 {
     struct ext4_sblock *sb = &bg_ref->fs->sb;
 
-    uint32_t inode_size          = ext4_get32(sb, inode_size);
-    uint32_t block_size          = ext4_sb_get_block_size(sb);
+    uint32_t inode_size = ext4_get32(sb, inode_size);
+    uint32_t block_size = ext4_sb_get_block_size(sb);
     uint32_t inodes_per_block = block_size / inode_size;
     uint32_t inodes_in_group  = ext4_inodes_in_group_cnt(sb, bg_ref->index);
     uint32_t table_blocks = inodes_in_group / inodes_per_block;
@@ -444,6 +433,26 @@ static int ext4_fs_init_inode_table(struct ext4_block_group_ref *bg_ref)
     return EOK;
 }
 
+static uint64_t ext4_fs_get_descriptor_block(struct ext4_sblock *s,
+        uint32_t bgid, uint32_t dsc_per_block)
+{
+    uint32_t first_meta_bg, dsc_id;
+
+    int has_super = 0;
+
+    dsc_id = bgid / dsc_per_block;
+    first_meta_bg = ext4_sb_first_meta_bg(s);
+
+    if (!ext4_sb_has_feature_incompatible(s, EXT4_FEATURE_INCOMPAT_META_BG) ||
+            dsc_id < first_meta_bg)
+        return ext4_get32(s, first_data_block) + dsc_id + 1;
+
+    if (ext4_sb_is_super_in_bg(s, bgid))
+        has_super = 1;
+
+    return (has_super + ext4_fs_first_bg_block_no(s, bgid));
+}
+
 
 int ext4_fs_get_block_group_ref(struct ext4_fs *fs, uint32_t bgid,
     struct ext4_block_group_ref *ref)
@@ -453,14 +462,12 @@ int ext4_fs_get_block_group_ref(struct ext4_fs *fs, uint32_t bgid,
             ext4_sb_get_desc_size(&fs->sb);
 
     /* Block group descriptor table starts at the next block after superblock */
-    uint64_t block_id = ext4_get32(&fs->sb, first_data_block) + 1;
+    uint64_t block_id = ext4_fs_get_descriptor_block(&fs->sb, bgid,
+            dsc_per_block);
 
-    /* Find the block containing the descriptor we are looking for */
-    block_id += bgid / dsc_per_block;
     uint32_t offset = (bgid % dsc_per_block) *
             ext4_sb_get_desc_size(&fs->sb);
 
-
     int rc = ext4_block_get(fs->bdev, &ref->block, block_id);
     if (rc != EOK)
         return rc;
@@ -512,6 +519,12 @@ int ext4_fs_get_block_group_ref(struct ext4_fs *fs, uint32_t bgid,
     return EOK;
 }
 
+/**@brief  Compute checksum of block group descriptor.
+ * @param sb   Superblock
+ * @param bgid Index of block group in the filesystem
+ * @param bg   Block group to compute checksum for
+ * @return Checksum value
+ */
 static uint16_t ext4_fs_bg_checksum(struct ext4_sblock *sb, uint32_t bgid,
     struct ext4_bgroup *bg)
 {
@@ -519,10 +532,10 @@ static uint16_t ext4_fs_bg_checksum(struct ext4_sblock *sb, uint32_t bgid,
     uint16_t crc = 0;
 
     /* Compute the checksum only if the filesystem supports it */
-    if (ext4_sb_check_read_only(sb,
+    if (ext4_sb_has_feature_read_only(sb,
             EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
-        void *base = bg;
-        void *checksum = &bg->checksum;
+        uint8_t  *base = (uint8_t  *)bg;
+        uint8_t  *checksum = (uint8_t  *)&bg->checksum;
 
         uint32_t offset = (uint32_t) (checksum - base);
 
@@ -542,7 +555,7 @@ static uint16_t ext4_fs_bg_checksum(struct ext4_sblock *sb, uint32_t bgid,
         offset += sizeof(bg->checksum);
 
         /* Checksum of the rest of block group descriptor */
-        if ((ext4_sb_check_feature_incompatible(sb,
+        if ((ext4_sb_has_feature_incompatible(sb,
                 EXT4_FEATURE_INCOMPAT_64BIT)) &&
                 (offset < ext4_sb_get_desc_size(sb)))
 
@@ -678,7 +691,7 @@ int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref,
         mode = 0777;
         mode |= EXT4_INODE_MODE_DIRECTORY;
         ext4_inode_set_mode(&fs->sb, inode, mode);
-        ext4_inode_set_links_count(inode, 1);  /* '.' entry */
+        ext4_inode_set_links_count(inode, 0);
 
     } else {
         /*
@@ -689,16 +702,17 @@ int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref,
         mode = 0666;
         mode |= EXT4_INODE_MODE_FILE;
         ext4_inode_set_mode(&fs->sb, inode, mode);
-        ext4_inode_set_links_count(inode, 0);
+        ext4_inode_set_links_count(inode, 1);
     }
 
+
     ext4_inode_set_uid(inode, 0);
     ext4_inode_set_gid(inode, 0);
     ext4_inode_set_size(inode, 0);
-    ext4_inode_set_access_time(inode,          0);
+    ext4_inode_set_access_time(inode, 0);
     ext4_inode_set_change_inode_time(inode, 0);
     ext4_inode_set_modification_time(inode, 0);
-    ext4_inode_set_deletion_time(inode,        0);
+    ext4_inode_set_deletion_time(inode, 0);
     ext4_inode_set_blocks_count(&fs->sb, inode, 0);
     ext4_inode_set_flags(inode, 0);
     ext4_inode_set_generation(inode, 0);
@@ -709,7 +723,7 @@ int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref,
 
 #if CONFIG_EXTENT_ENABLE
     /* Initialize extents if needed */
-    if (ext4_sb_check_feature_incompatible(
+    if (ext4_sb_has_feature_incompatible(
             &fs->sb, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
         ext4_inode_set_flag(inode, EXT4_INODE_FLAG_EXTENTS);
 
@@ -740,7 +754,7 @@ int ext4_fs_free_inode(struct ext4_inode_ref *inode_ref)
     uint32_t suboffset;
 #if CONFIG_EXTENT_ENABLE
     /* For extents must be data block destroyed by other way */
-    if ((ext4_sb_check_feature_incompatible(&fs->sb,
+    if ((ext4_sb_has_feature_incompatible(&fs->sb,
             EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
             (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))){
         /* Data structures are released during truncate operation... */
@@ -762,7 +776,7 @@ int ext4_fs_free_inode(struct ext4_inode_ref *inode_ref)
     uint32_t block_size = ext4_sb_get_block_size(&fs->sb);
     uint32_t count = block_size / sizeof(uint32_t);
 
-    struct     ext4_block  block;
+    struct ext4_block  block;
 
     /* 2) Double indirect */
     fblock = ext4_inode_get_indirect_block(inode_ref->inode, 1);
@@ -793,7 +807,7 @@ int ext4_fs_free_inode(struct ext4_inode_ref *inode_ref)
     }
 
     /* 3) Tripple indirect */
-    struct     ext4_block  subblock;
+    struct ext4_block  subblock;
     fblock = ext4_inode_get_indirect_block(inode_ref->inode, 2);
     if (fblock != 0) {
         int rc = ext4_block_get(fs->bdev, &block, fblock);
@@ -845,8 +859,9 @@ int ext4_fs_free_inode(struct ext4_inode_ref *inode_ref)
 
         ext4_inode_set_indirect_block(inode_ref->inode, 2, 0);
     }
-
+#if CONFIG_EXTENT_ENABLE
     finish:
+#endif
     /* Mark inode dirty for writing to the physical device */
     inode_ref->dirty = true;
 
@@ -902,7 +917,7 @@ int ext4_fs_truncate_inode(struct ext4_inode_ref *inode_ref,
     if (old_size % block_size != 0)
         old_blocks_count++;
 #if CONFIG_EXTENT_ENABLE
-    if ((ext4_sb_check_feature_incompatible(sb,
+    if ((ext4_sb_has_feature_incompatible(sb,
             EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
             (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
 
@@ -947,7 +962,7 @@ int ext4_fs_get_inode_data_block_index(struct ext4_inode_ref *inode_ref,
     uint32_t current_block;
 #if CONFIG_EXTENT_ENABLE
     /* Handle i-node using extents */
-    if ((ext4_sb_check_feature_incompatible(&fs->sb,
+    if ((ext4_sb_has_feature_incompatible(&fs->sb,
             EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
             (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
 
@@ -996,7 +1011,7 @@ int ext4_fs_get_inode_data_block_index(struct ext4_inode_ref *inode_ref,
         return EOK;
     }
 
-    struct     ext4_block block;
+    struct ext4_block block;
 
     /*
      * Navigate through other levels, until we find the block number
@@ -1048,7 +1063,7 @@ int ext4_fs_set_inode_data_block_index(struct ext4_inode_ref *inode_ref,
 
 #if CONFIG_EXTENT_ENABLE
     /* Handle inode using extents */
-    if ((ext4_sb_check_feature_incompatible(&fs->sb,
+    if ((ext4_sb_has_feature_incompatible(&fs->sb,
             EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
             (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
         /* Not reachable */
@@ -1090,8 +1105,8 @@ int ext4_fs_set_inode_data_block_index(struct ext4_inode_ref *inode_ref,
 
     uint32_t new_block_addr;
 
-    struct     ext4_block block;
-    struct     ext4_block new_block;
+    struct ext4_block block;
+    struct ext4_block new_block;
 
     /* Is needed to allocate indirect block on the i-node level */
     if (current_block == 0) {
@@ -1206,7 +1221,7 @@ int ext4_fs_release_inode_block(struct ext4_inode_ref *inode_ref,
     struct ext4_fs *fs = inode_ref->fs;
 
     /* Extents are handled otherwise = there is not support in this function */
-    ext4_assert(!(ext4_sb_check_feature_incompatible(&fs->sb,
+    ext4_assert(!(ext4_sb_has_feature_incompatible(&fs->sb,
             EXT4_FEATURE_INCOMPAT_EXTENTS) &&
             (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))));
 
@@ -1249,7 +1264,7 @@ int ext4_fs_release_inode_block(struct ext4_inode_ref *inode_ref,
      * Navigate through other levels, until we find the block number
      * or find null reference meaning we are dealing with sparse file
      */
-    struct     ext4_block block;
+    struct ext4_block block;
 
     while (level > 0) {
 
@@ -1304,7 +1319,7 @@ int ext4_fs_append_inode_block(struct ext4_inode_ref *inode_ref,
 {
 #if CONFIG_EXTENT_ENABLE
     /* Handle extents separately */
-    if ((ext4_sb_check_feature_incompatible(&inode_ref->fs->sb,
+    if ((ext4_sb_has_feature_incompatible(&inode_ref->fs->sb,
             EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
             (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))){
         return ext4_extent_append_block(inode_ref, iblock, fblock, true);
@@ -1347,6 +1362,52 @@ int ext4_fs_append_inode_block(struct ext4_inode_ref *inode_ref,
     return EOK;
 }
 
+void ext4_fs_inode_links_count_inc(struct ext4_inode_ref *inode_ref)
+{
+    uint16_t link;
+    if(!ext4_inode_is_type(&inode_ref->fs->sb, inode_ref->inode,
+                EXT4_INODE_MODE_DIRECTORY)){
+        ext4_inode_set_links_count(inode_ref->inode, 0);
+        return;
+    }
+
+    link = ext4_inode_get_links_count(inode_ref->inode);
+    link++;
+    ext4_inode_set_links_count(inode_ref->inode, link);
+
+
+    bool is_dx = ext4_sb_has_feature_compatible(&inode_ref->fs->sb,
+            EXT4_FEATURE_COMPAT_DIR_INDEX) &&
+                 ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_INDEX);
+
+    if(is_dx &&  link > 1){
+        if(link >= EXT4_LINK_MAX || link == 2){
+            ext4_inode_set_links_count(inode_ref->inode, 1);
+
+            uint32_t v = ext4_get32(&inode_ref->fs->sb, features_read_only);
+            v |= EXT4_FEATURE_RO_COMPAT_DIR_NLINK;
+            ext4_set32(&inode_ref->fs->sb, features_read_only, v);
+        }
+    }
+}
+
+void ext4_fs_inode_links_count_dec(struct ext4_inode_ref *inode_ref)
+{
+    if(!ext4_inode_is_type(&inode_ref->fs->sb, inode_ref->inode,
+                EXT4_INODE_MODE_DIRECTORY)){
+        ext4_inode_set_links_count(inode_ref->inode, 0);
+        return;
+    }
+
+    uint16_t links = ext4_inode_get_links_count(inode_ref->inode);
+
+
+    if(links > 2)
+        ext4_inode_set_links_count(inode_ref->inode, links - 1);
+
+}
+
+
 /**
  * @}
  */