所有的准备⼯作都已经做完,是时候认识下⽂件系统了。我们想要在硬盘上储⽂件,必须先把硬盘格式化为某种格式的⽂件系统,才能存储⽂件。⽂件系统的⽬的就是组织和管理硬盘中的⽂件。在Linux 系统中,最常⻅的是ext2
系列的⽂件系统。其早期版本为ext2,后来⼜发展出ext3
和ext4
。ext3
和ext4
虽然对ext2
进⾏了增强,但是其核⼼设计并没有发⽣变化,我们仍是以较⽼的ext2作为演⽰对象。
ext2⽂件系统将整个分区划分成若⼲个同样⼤⼩的块组(BlockGroup),如下图所⽰。只要能管理⼀个分区就能管理所有分区,也就能管理所有磁盘⽂件。
上图中启动块(BootBlock/Sector)的⼤⼩是确定的,为1KB,由PC标准规定,⽤来存储磁盘分区信息和启动信息,任何⽂件系统都不能修改启动块。启动块之后才是ext2⽂件系统的开始。
ext2
⽂件系统会根据分区的⼤⼩划分为数个BlockGroup
。⽽每个BlockGroup
都有着相同的结构组成。
政府管理各区的例⼦:
存放⽂件系统本⾝的结构信息,描述整个分区的⽂件系统信息。记录的信息主要有:bolck和inode的总量,未使⽤的block和inode的数量,⼀个block和inode的⼤⼩,最近⼀次挂载的时间,最近⼀次写⼊数据的时间,最近⼀次检验磁盘的时间等其他⽂件系统的相关信息。SuperBlock的信息被破坏,可以说整个⽂件系统结构就被破坏了
超级块在每个块组的开头都有⼀份拷⻉(第⼀个块组必须有,后⾯的块组可以没有)。为了保证⽂ 件系统在磁盘部分扇区出现物理问题的情况下还能正常⼯作,就必须保证⽂件系统的superblock信 息在这种情况下也能正常访问。所以⼀个⽂件系统的superblock会在多个blockgroup中进⾏备份, 这些superblock区域的数据保持⼀致。
/*
* Structure of the super block
*/
struct ext2_super_block
{
__le32 s_inodes_count;
/* Inodes count */
__le32 s_blocks_count;
/* Blocks count */
__le32 s_r_blocks_count; /* Reserved blocks count */
__le32 s_free_blocks_count;
/* Free blocks count */
__le32 s_free_inodes_count;
__le32 s_first_data_block;
/* Free inodes count */
/* First Data Block */
__le32 s_log_block_size; /* Block size */
__le32 s_log_frag_size;
/* Fragment size */
__le32 s_blocks_per_group;
/* # Blocks per group */
__le32 s_frags_per_group; /* # Fragments per group */
__le32 s_inodes_per_group;
__le32 s_mtime;
__le32 s_wtime;
__le16 s_mnt_count;
/* # Inodes per group */
/* Mount time */
/* Write time */
/* Mount count */
__le16 s_max_mnt_count;
__le16 s_magic;
__le16 s_state;
__le16 s_errors;
/* Maximal mount count */
/* Magic signature */
/* File system state */
/* Behaviour when detecting errors */
__le16 s_minor_rev_level; /* minor revision level */
__le32 s_lastcheck;
__le32 s_checkinterval;
__le32 s_creator_os;
__le32 s_rev_level;
__le16 s_def_resuid;
__le16 s_def_resgid;
/* time of last check */
/* max. time between checks */
/* OS */
/* Revision level */
/* Default uid for reserved blocks */
/* Default gid for reserved blocks */
/*
* These fields are for EXT2_DYNAMIC_REV superblocks only.
*
* Note: the difference between the compatible feature set and
* the incompatible feature set is that if there is a bit set
* in the incompatible feature set that the kernel doesn't
* know about, it should refuse to mount the filesystem.
*
* e2fsck's requirements are more strict; if it doesn't know
* about a feature in either the compatible or incompatible
* feature set, it must abort and not try to meddle with
* things it doesn't understand...
*/
__le32 s_first_ino; /* First non-reserved inode */
__le16 s_inode_size; /* size of inode structure */
__le16 s_block_group_nr; /* block group # of this superblock */
__le32 s_feature_compat; /* compatible feature set */
__le32 s_feature_incompat; /* incompatible feature set */
__le32 s_feature_ro_compat; /* readonly-compatible feature set */
__u8 s_uuid[16]; /* 128-bit uuid for volume */
char s_volume_name[16]; /* volume name */
char s_last_mounted[64]; /* directory where last mounted */
__le32 s_algorithm_usage_bitmap; /* For compression */
/*
* Performance hints. Directory preallocation should only
* happen if the EXT2_COMPAT_PREALLOC flag is on.
*/
__u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
__u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
__u16 s_padding1;
/*
* Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set.
*/
__u8 s_journal_uuid[16]; /* uuid of journal superblock */
__u32 s_journal_inum; /* inode number of journal file */
__u32 s_journal_dev; /* device number of journal file */
__u32 s_last_orphan; /* start of list of inodes to delete */
__u32 s_hash_seed[4]; /* HTREE hash seed */
__u8 s_def_hash_version; /* Default hash version to use */
__u8 s_reserved_char_pad;
__u16 s_reserved_word_pad;
__le32 s_default_mount_opts;
__le32 s_first_meta_bg; /* First metablock block group */
__u32 s_reserved[190]; /* Padding to the end of the block */
};
块组描述符表,描述块组属性信息,整个分区分成多个块组就对应有多少个块组描述符。每个块组描述符存储⼀个块组的描述信息,如在这个块组中从哪⾥开始是inodeTable,从哪⾥开始是Data Blocks
,空闲的inode
和数据块还有多少个等等。块组描述符在每个块组的开头都有⼀份拷⻉。
// 磁盘级blockgroup的数据结构
/*
* Structure of a blocks group descriptor
*/
struct ext2_group_desc
{
__le32 bg_block_bitmap;/* Blocks bitmap block */
__le32 bg_inode_bitmap;/* Inodes bitmap */
__le16 bg_free_blocks_count; /* Inodes table block*/
__le32 bg_inode_table;/* Free blocks count */
__le16 bg_free_inodes_count;/* Free inodes count */
__le16 bg_used_dirs_count; /* Directories count */
__le16 bg_pad;
__le32 bg_reserved[3];
};
BlockBitmap中记录着DataBlock中哪个数据块已经被占⽤,哪个数据块没有被占⽤
每个bit表⽰⼀个inode是否空闲可⽤。
数据区:存放⽂件内容,也就是⼀个⼀个的Block。根据不同的⽂件类型有以下⼏种情况:
ls-l
命令看到的其它信息保存在该⽂件的inode中。inode
内部存在_ _le32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */ , EXT2_N_BLOCKS =15
,就是⽤来进⾏inode和block映射的
思考:
请解释:知道inode
号的情况下,在指定分区,请解释:对⽂件进⾏增、删、查、改是在做什么?
i_block
数组,它用于存储文件数据块的指针。对于小文件,文件数据可能直接通过i_block
数组中的直接指针指向的数据块来读取。i_block
数组中剩余的直接指针来指向新分配的数据块。i_block
指针,找到文件所占用的数据块。然后将这些数据块在块位图中的对应位设置为0,表示这些块已经空闲,可以被重新分配。i_block
指针找到文件的数据块,直接在这些数据块中修改文件内容即可。i_block
指针(如果有指针指向了释放的数据块,需要进行调整),最后修改剩余数据块中的文件内容。🔴结论:
下⾯,通过touch⼀个新⽂件来看看如何⼯作。
[root@localhost linux]# touch abc
[root@localhost linux]# ls -i abc
263466 abc
创建⼀个新⽂件主要有以下4个操作: