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");
}
}
{
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");
}
}
/*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");
/*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");
*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;
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 */
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;
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)
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;
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)
{
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);
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)))
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 {
/*
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);
#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);
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... */
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);
}
/* 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);
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;
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))) {
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))) {
return EOK;
}
- struct ext4_block block;
+ struct ext4_block block;
/*
* Navigate through other levels, until we find the block number
#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 */
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) {
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))));
* 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) {
{
#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);
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);
+
+}
+
+
/**
* @}
*/