mkfs.ext4 - What it actually creates

September 26, 2023 | 8 minute read
Text Size 100%:

Introduction

The mke2fs utility is used to create ext2, ext3, and ext4 filesystems. Depending on the preferred filesystem, you can run mkfs.XXX <device> , where XXX can be ext2, ext3, or ext4, indicating the specific filesystem type to be created. This utility is included in the e2fsprogs rpm package.

When you run mkfs.ext4, it writes important data onto the disk that provides information about the structure of the filesystem. mkfs.ext4 creates several data structures on the disk, which include:

  • Superblock: Contains important metadata about the filesystem.
  • Group descriptors: Stores information about each block group in the filesystem.
  • Block bitmap: Keeps track of which data blocks are in use or free.
  • Inode bitmap: Tracks the allocation status of inodes (data structures representing files and directories).
  • Inode table: Stores detailed information about each inode in the filesystem.
  • Journal: Manages the journaling feature for filesystem consistency.

In this blog, we explore how many blocks or how much memory is allocated for each of these data structures. Additionally, we will delve into the calculation that determines the memory allocated for each specific structure.

mke2fs.conf

/etc/mke2fs.conf is a configuration file for mke2fs. It contains default settings for ext2, ext3, and ext4 filesystems. This file can be modified to change the default settings, or you can to override them by specifying preferred options as command line arguments when using the mkfs command.

Let’s examine the contents of the /etc/mke2fs.conf file.
Note: The contents relevant to the ext4 filesystem are displayed

[defaults]
        base_features = sparse_super,large_file,filetype,resize_inode,dir_index,ext_attr
        default_mntopts = acl,user_xattr
        enable_periodic_fsck = 0
        blocksize = 4096
        inode_size = 256
        inode_ratio = 16384

[fs_types]
        ...
        ext4 = {
                features = has_journal,extent,huge_file,flex_bg,metadata_csum,64bit,dir_nlink,extra_isize
                inode_size = 256
        }
        ...

By default, the features base_features, and features are enabled in mkfs.ext4. However, you can disable or enable these features when you run mkfs.ext4. Periodic fsck is disabled by default. The default block size is set to 4096 bytes, the inode size is 256 bytes, and the inode ratio is 16384.

The values blocksize, inode_size, and inode_ratio are important as they determine the number of blocks, block groups, and inodes in a filesystem. Among these, blocksize and inode_size are self-explanatory, but inode_ratio needs some explanation.

The inode_ratio parameter indicates the number of bytes for which an inode is created. That is, an inode is created for every inode_ratio bytes. In our case, with an inode_ratio of 16384, mkfs.ext4 creates an inode for every 16384 bytes.

For example, on a 1GiB device, running mkfs.ext4 would create 65536 inodes in the filesystem, because 1GiB/16384 = 65536. That is, an inode is created for every 16384 bytes.

Therefore, the number of inodes in a filesystem is determined by the formula (filesystem size)/(inode_ratio).

A graphical view of data structures

Graphical View
Graphical View

Superblock

The ext4 Superblock has a size of 1024 bytes. In a filesytem with a 4k bytes block size, Superblock is placed at 1025th byte of the device, the first 1024 bytes are reserved for installation of boot sectors and other purposes. And the remaining 2048 bytes are unused.

Group Descriptors

The Block group descriptor stores important statistics related to its corresponding block group. The number of block group descriptors matches the number of block groups present in the filesystem. The collection of all block group descriptors is referred to as the Group Descriptor Table (GDT). The block immediately following the Superblock is used by the GDT, and the entire block is allocated solely for this purpose.

Block Bitmap and Inode Bitmap

The Block bitmap tracks the usage of all blocks in the filesystem. When a block is in use or reserved for something, the corresponding bit in the block bitmap is set.

Similarly, the Inode bitmap tracks the status of inodes. If an inode is in use, its corresponding bit in the inode bitmap is set.

Each block group in the filesystem has its own block bitmap and inode bitmap. Therefore, the number of block bitmaps is equal to the number of inode bitmaps, which is also equal to the number of block groups.

Since each bitmap occupies a block of memory, the total number of blocks allocated for the bitmaps is equal to twice the number of block groups.

Inode Table

The Inode table is a table of all the inodes in a block group. The size of each inode table is determined by multiplying the number of inodes in the block group by the size of each individual inode.

For example, let’s consider a 1 Gib filesystem with a blocksize of 4k (4096 bytes), an inode_ratio of 16384, and an inode_size of 256 bytes. In this case, there are 8192 inodes in each block group. Therefore, the size of each inode table will be 2 Mib (8192 * 256).

To calculate the total number of blocks reserved for all the inode tables, you need to divide the product of the number of block groups and the size of each inode table with the blocksize. (size of each inode table) * (number of block groups)/blocksize.

Journal

In a filesystem with the journaling feature, some blocks are set aside for journaling. The exact number of reserved blocks depends on the size of the filesystem. The following table shows the number of blocks reserved for filesystems of various sizes. The first block within these reserved blocks is initialized with the journal superblock.

 

Number of blocks in a filesystem
Blocks reserved for the journal
< 2048
0 (No journaling)
< 32768
1024
< 256*1024
4096
< 512*1024
8192
< 4096*1024
16384
<8192*1024
32768
< 16384*1024
65536
<32768*1024
131072
> 32768*1024
262144

 

Contents of a fresh filesystem

When the sparse_super feature is enabled, backup copies of the superblock and group descriptor table (GDT) are stored in the block groups numbering in powers of 3, 5, 7 (For example: 3, 9, 25, 27, 49,.. etc). On the other hand, if the sparse_super feature is disabled, backup copies of the superblock and GDT are stored in all block groups of the filesystem.

The /proc/fs/ext4/<device-name>/mb_groups file provides information about the filesystem’s buddy system. It also gives details about the number of free blocks available in the filesystem.

The columns in the mb_groups file are as follows:

  • Group: Indicates the block group number.
  • Free: Represents the number of free blocks within the block group.
  • Frags: Indicates the number of free fragments within the block group.
  • First: Denotes the first available block number in the block group.
  • [20 to 213]: This series of values represents the availability of different-sized chunks within the block group.

By examining the contents of the mb_groups file in a fresh filesystem, we can understand how the blocks are being used for different purposes.

Let’s examine two examples of a filesystem with a size of 1GiB, where one has the sparse_super feature enabled and the other has it disabled. 

FS with sparse_super enabled

The image displays the contents of mb_groups on a newly created filesystem with the sparse_super feature enabled.

mb_groups1

Here’s an analysis of the block usage in each block group:

Block Group 0:

Purpose
No. of blocks used
Superblock
1
Group Descriptor Table (GDT)
1
Reserved GDT blocks
127 (this number is given by s_reserved_gdt_blocks member of ext4_super_block, these are part of resize inode)
Block bitmaps
8 (1 for each block group)
Inode bitmaps
8 (1 for each block group)
Inode Table
4096 (65536 inodes, each occupying 256 bytes)
Root Directory
1
lost+found
4
resize inode (inode no. 7)
1
Total
4247

 

Block Groups 1, 3, 5, 7:

Purpose
No. of blocks used
Backup superblock
1
Backup GDT
1
Backup reserved GDT blocks
127
Total
129

 

Block group 4: A 1 GiB FS has 524288 blocks, thus 8192 blocks allocated for journal purposes (See the table in journal section).

Block group 2, 6: No blocks are used in these block groups.

FS with sparse_super disabled

The image shows the contents of mb_groups on a newly created filesystem with the sparse_super  feature disabled.

mb_groups2

Here’s an analysis of the block usage in each block group:

Block Group 0: 

Purpose
No. of blocks used
Superblock
1
Group Descriptor Table (GDT)
1
Reserved GDT blocks
0 (Feature resize_inode is not supported when sparse_super is disabled.)
Block bitmaps
8 (1 for each block group)
Inode bitmaps
8 (1 for each block group)
Inode Table
4096 (65536 inodes, each occupying 256 bytes)
Root Directory
1
lost+found
4
resize inode (inode no. 7)
0 (resize_inode is disabled)
Total
4119

 

Block Group 3:

Purpose
No. of blocks used
Backup superblock
1
Backup GDT
1
Journal
8192
Total
8194

 

Block Groups 1, 2, 4, 5, 6, 7:

Purpose
No. of blocks used
Backup superblock
1
Backup GDT
1
Total
2

 

Conclusion

We took a closer look at the different data structures created by the mkfs command and their memory allocation. These include important components like the superblock, group descriptors, block and inode bitmaps, inode tables, journal superblocks, and more. Knowing the amount of memory reserved/allocated for these different things allows us to understand the filesystem internals better.

References

  • Manual pages of mke2fs, mke2fs.conf

Srivathsa Dara


Previous Post

An In-Depth Look at Pipe and Splice implementation in Linux kernel

Shoily Rahman | 33 min read

Next Post


Learn to launch Oracle Database 23c Free–Developer Release on Oracle Linux

Nicolas Pares | 3 min read