The first block in each Ext2 partition is never managed by the Ext2 filesystem,
because it is reserved for the partition boot sector.
The rest of the Ext2 partition is split into block groups,
each of which has the layout shown in Image 2.
As you will notice from the figure, some data structures must fit in exactly one block,
while others may require more than one block.
All the block groups in the filesystem have the same size and are stored sequentially,
thus the kernel can derive the location of a block group in a disk simply from its integer index.
ext2 partition.
| Boot Block | Block Group 0 | - - - - - | Block Group n |
Single ext2 block group.
| Super Block | Group Descriptors | Data Block Bitmap | Inode Bitmap | Inode Table | Data Blocks |
As you can see Super Block and Group Descriptors are duplicated in each block group.
This is done because to maintain the redundancy. If any crash occures,we can easily replace the super block
and group descriptor from some other partition.
In this article we'll descuss super block according to programming point of view.
We'll see how to read the super block.
Ofcourse there are library called libext2fs which can give us all above data structure easily.
But don't forget the title of this article, we are about to understand the things inside ext2.
In further documents I'll explore other data structures too.
An Ext2 disk superblock is stored in an ext2_super_block structure, whose fields are listed below
s_inodes_count : Total number of inodes
s_blocks_count : Filesystem size in blocks
s_r_blocks_count : Number of reserved blocks
s_free_blocks_count : Free blocks counter
s_free_inodes_count : Free inodes counter
s_first_data_block : Number of first useful block (always 1)
s_log_block_size : Block size
s_log_frag_size : Fragment size
s_blocks_per_group : Number of blocks per group
s_frags_per_group : Number of fragments per group
s_inodes_per_group : Number of inodes per group
s_mtime : Time of last mount operation
s_wtime : Time of last write operation
s_mnt_count : Mount operations counter
s_max_mnt_count : Number of mount operations before check
s_magic : Magic signature
s_state : Status flag
s_errors : Behavior when detecting errors
s_minor_rev_level : Minor revision level
s_lastcheck : Time of last check
s_checkinterval : Time between checks
s_creator_os : OS where filesystem was created
s_rev_level : Revision level of the filesystem
s_def_resuid : Default UID for reserved blocks
s_def_resgid : Default user group ID for reserved blocks
s_first_ino : Number of first nonreserved inode
s_inode_size : Size of on-disk inode structure
s_block_group_nr : Block group number of this superblock
s_feature_compat : Compatible features bitmap
s_feature_incompat : Incompatible features bitmap
s_feature_ro_compat : Read-only compatible features bitmap
s_uuid : 128-bit filesystem identifier
s_volume_name : Volume name
s_last_mounted : Pathname of last mount point
s_algorithm_usage_bitmap : Used for compression
s_prealloc_blocks : Number of blocks to preallocate
s_prealloc_dir_blocks : Number of blocks to preallocate for directories
s_padding1 : Alignment to word
s_reserved : Nulls to pad out 1,024 bytes
Very small structure isn't it?
Now we'll see the code to access the super block.
Expand|Select|Wrap|Line Numbers
- #include<linux/ext2_fs.h>
- #include<sys/types.h>
- #include<sys/stat.h>
- #include<stdio.h>
- #include<unistd.h>
- #include<fcntl.h>
- #include<stdlib.h>
- #include<string.h>
- #define boot_block_size 1024
- int main()
- {
- char *buff = (char *)malloc(sizeof(struct ext2_super_block));
- struct ext2_super_block * sblock = (struct ext2_super_block *)malloc(sizeof(struct ext2_super_block));
- //open any partition for testing,must be ext2/ext3.
- int fd = open("/dev/hda3",O_RDONLY);
- //skip the boot block
- lseek(fd,boot_block_size,SEEK_CUR);
- //read the superblock raw data from disk to buff
- read(fd,buff,sizeof(struct ext2_super_block));
- //copy buffer to sblock, you can use casting or union for this.
- memcpy((void *)sblock,(void *)buff,sizeof(struct ext2_super_block));
- printf("\nmagic number:%u\n",sblock->s_magic);
- close(fd);
- return 0;
- }
I'll show you how to read group descriptors in next article