In linux, any file has an inode corresponding to it. That is to say, in a file system, a file has a unique ino to mark it, in the ext4 system, how does ino determine?
When we create a new file or directory, the ext4_create function is called. The call path is ext4_create-> ext4_new_inode. The inode-> ino is defined in the ext4_new_inode function.
Analysis Function ext4_new_inode
Struct inode * _ ext4_new_inode (handle_t * handle, struct inode * dir,
Umode_t mode, const struct qstr * qstr,
_ U32 goal, uid_t * owner, int handle_type,
Unsigned int line_no, int nblocks)
{
...
For (I = 0; I <ngroups; I ++, ino = 0 ){
Err =-EIO;
Gdp = ext4_get_group_desc (sb, group, & group_desc_bh );
If (! Gdp)
Goto out;
/* 1. check whether there is free indode before loading inode bitmap */
If (ext4_free_inodes_count (sb, gdp) = 0 ){
If (++ group = ngroups)
Group = 0;
Continue;
}
...
/* 1. check whether there is free indode before loading inode bitmap */
Ino = ext4_find_next_zero_bit (unsigned long *)
Inode_bitmap_bh-> B _data,
EXT4_INODES_PER_GROUP (sb), ino );
Struct inode * _ ext4_new_inode (handle_t * handle, struct inode * dir,
Umode_t mode, const struct qstr * qstr,
_ U32 goal, uid_t * owner, int handle_type,
Unsigned int line_no, int nblocks)
{
...
For (I = 0; I <ngroups; I ++, ino = 0 ){
Err =-EIO;
Gdp = ext4_get_group_desc (sb, group, & group_desc_bh );
If (! Gdp)
Goto out;
/* 1. check whether there is free indode before loading inode bitmap */
If (ext4_free_inodes_count (sb, gdp) = 0 ){
If (++ group = ngroups)
Group = 0;
Continue;
}
...
Inode_bitmap_bh = ext4_read_inode_bitmap (sb, group );
...
/* 2. In the inode bitmap, find the next 0 bit starting with ino + 1 */
Ino = ext4_find_next_zero_bit (unsigned long *)
Inode_bitmap_bh-> B _data,
EXT4_INODES_PER_GROUP (sb), ino );
/* 3. Check whether free inode is valid: (1) greater than inode_per_group, (2) smaller than first_ino */
If (ino> = EXT4_INODES_PER_GROUP (sb ))
Goto next_group;
If (group = 0 & (ino + 1) <EXT4_FIRST_INO (sb )){
Ext4_error (sb, "reserved inode found cleared -"
"Inode = % lu", ino + 1 );
Continue;
}
...
/* 4. Update inode bitmap. If inode bitmap update fails, search again */
Ext4_lock_group (sb, group );
Ret2 = ext4_test_and_set_bit (ino, inode_bitmap_bh-> B _data );
Ext4_unlock_group (sb, group );
Ino ++;/* the inode bitmap is zero-based */
If (! Ret2)
Goto got;/* we grabbed the inode! */
Next_inode:
If (ino <EXT4_INODES_PER_GROUP (sb ))
Goto repeat_in_this_group;
Next_group:
If (++ group = ngroups)
Group = 0;
}
...
/* 5. Update the free_inodes_count variable in the group */
Ext4_free_inodes_set (sb, gdp, ext4_free_inodes_count (sb, gdp)-1 );
If (S_ISDIR (mode )){
Ext4_used_dirs_set (sb, gdp, ext4_used_dirs_count (sb, gdp) + 1 );
If (sbi-> s_log_groups_per_flex ){
Ext4_group_t f = ext4_flex_group (sbi, group );
Atomic_inc (& sbi-> s_flex_groups [f]. used_dirs );
}
}
If (ext4_has_group_desc_csum (sb )){
Ext4_inode_bitmap_csum_set (sb, group, gdp, inode_bitmap_bh,
EXT4_INODES_PER_GROUP (sb)/8 );
Ext4_group_desc_csum_set (sb, group, gdp );
}
Ext4_unlock_group (sb, group );
...
/* 6. Get inode-> ino */
Inode-> I _ino = ino + group * EXT4_INODES_PER_GROUP (sb );
...
}
Steps:
1. check whether there is free indode before loading inode bitmap.
2. In the inode bitmap, find the next 0 bit starting with ino + 1.
3. Check whether free inode is valid: (1) greater than inode_per_group, (2) smaller than first_ino
4. Update inode bitmap. update failed and search again
5. Update the free_inodes_count variable in the group.
6. Get inode-> ino.
Therefore, you can use inode-> ino to calculate the group and block of inode:
Group_id
= (Inode-> ino-1)/inodes_per_group
Inode_blkid
= First_inode_blk_in_group
+ (Inode> ino-1) % inodes_per_group)/(inodes_per_block );
Inode_offset
= First_inode_blk_in_group * blk_size
+ (Inode> ino-1) % inodes_per_group) * inode_size
Where:
The reason inode-> ino-1 is that ext4 system does not have file index 0
(1) inode-> ino: it can be obtained through stat file_name;
(2) inodes_per_group: the number of inode in each group. For details, see debugfs;
(3) first_inode_blk_in_group: indicates the start block id of the inode table, which can be obtained by debugfs;
(4) blk_size: Logical Block Size, which can be obtained by debugfs;
(5) inode_size: the size of the space required for an inode to be stored on the disk, which can be obtained by debugfs;
(6) inodes_per_block: the number of inodes that each block can store. You can use blk_size/inode_size to obtain inode_block;
Root @ ubuntu:/mnt/ext4 # debugfs/dev/sdc
Debugfs 1.42 (29-Nov-2011)
Debugfs: stats
Filesystem volume name: <none>
Last mounted on:/mnt/ext4
Filesystem UUID: 883c6632-e61d-4420-b309-0695f321cf9d
Filesystem magic number: 0xEF53
...
Inode count: 327680
...
Fragments per group: 32768
Inodes per group: 8192
Inode blocks per group: 512
...
First inode: 11
Inode size: 256
Required extra isize: 28
...
Group 0: block bitmap at 321, inode bitmap at 337,Inode tableAt 353
24217 free blocks, 8180 free inodes, 2 used directories, 8180 unused inodes
[Checksum 0x25aa]
Group 1: block bitmap at 322, inode bitmap at 338, inode table at 865
31423 free blocks, 8192 free inodes, 0 used directories, 8192 unused inodes
[Inode not init, Checksum 0x94f1]
Group 2: block bitmap at 323, inode bitmap at 339, inode table at 1377
32768 free blocks, 8192 free inodes, 0 used directories, 8192 unused inodes