内核版本:linux-4.1.27
inode
索引节点,记录文件的文件属性(mode,time),数据块个数(i_blocks_lo)和位置(i_block[])。
/*
* Structure of an inode on the disk
*/
struct ext4_inode {
__le16 i_mode; /* File mode */
__le16 i_uid; /* Low 16 bits of Owner Uid */
__le32 i_size_lo; /* Size in bytes */
__le32 i_atime; /* Access time */
__le32 i_ctime; /* Inode Change time */
__le32 i_mtime; /* Modification time */
__le32 i_dtime; /* Deletion Time */
__le16 i_gid; /* Low 16 bits of Group Id */
__le16 i_links_count; /* Links count */
__le32 i_blocks_lo; /* Blocks count */
__le32 i_flags; /* File flags */
union {
struct {
__le32 l_i_version;
} linux1;
struct {
__u32 h_i_translator;
} hurd1;
struct {
__u32 m_i_reserved1;
} masix1;
} osd1; /* OS dependent 1 */
__le32 i_block[EXT4_N_BLOCKS];/* Pointers to blocks */
__le32 i_generation; /* File version (for NFS) */
__le32 i_file_acl_lo; /* File ACL */
__le32 i_size_high;
__le32 i_obso_faddr; /* Obsoleted fragment address */
union {
struct {
__le16 l_i_blocks_high; /* were l_i_reserved1 */
__le16 l_i_file_acl_high;
__le16 l_i_uid_high; /* these 2 fields */
__le16 l_i_gid_high; /* were reserved2[0] */
__le16 l_i_checksum_lo;/* crc32c(uuid+inum+inode) LE */
__le16 l_i_reserved;
} linux2;
struct {
__le16 h_i_reserved1; /* Obsoleted fragment number/size which are removed in ext4 */
__u16 h_i_mode_high;
__u16 h_i_uid_high;
__u16 h_i_gid_high;
__u32 h_i_author;
} hurd2;
struct {
__le16 h_i_reserved1; /* Obsoleted fragment number/size which are removed in ext4 */
__le16 m_i_file_acl_high;
__u32 m_i_reserved2[2];
} masix2;
} osd2; /* OS dependent 2 */
__le16 i_extra_isize;
__le16 i_checksum_hi; /* crc32c(uuid+inum+inode) BE */
__le32 i_ctime_extra; /* extra Change time (nsec << 2 | epoch) */
__le32 i_mtime_extra; /* extra Modification time(nsec << 2 | epoch) */
__le32 i_atime_extra; /* extra Access time (nsec << 2 | epoch) */
__le32 i_crtime; /* File Creation time */
__le32 i_crtime_extra; /* extra FileCreationtime (nsec << 2 | epoch) */
__le32 i_version_hi; /* high 32 bits for 64-bit version */
};
i_flags,文件的标志,其中几个含义如下:
/*
* Inode flags
*/
#define EXT4_SECRM_FL 0x00000001 /* Secure deletion */安全删除,删除后会填充随机数
#define EXT4_UNRM_FL 0x00000002 /* Undelete */可恢复删除,删除文件后数据会保留一段时间内可恢复
#define EXT4_COMPR_FL 0x00000004 /* Compress file */
#define EXT4_SYNC_FL 0x00000008 /* Synchronous updates */同步写,在写内存过程中同步写入磁盘
i_blocks_lo,表示文件占用的数据块个数,数组i_block保存数据块地址,数组长度12+3=15,代码来源如下:
/*
* Constants relative to the data blocks
*/
#define EXT4_NDIR_BLOCKS 12
#define EXT4_IND_BLOCK EXT4_NDIR_BLOCKS
#define EXT4_DIND_BLOCK (EXT4_IND_BLOCK + 1)
#define EXT4_TIND_BLOCK (EXT4_DIND_BLOCK + 1)
#define EXT4_N_BLOCKS (EXT4_TIND_BLOCK + 1)
数组长度15只能存储4K block容量为60KB大小的文件,明显不合理,为此前12项直接存储块地址,后3项依次为1级指针、2级指针、3级指针,如下图所示:
通过3级指针存储块地址转换,最大可存储文件大小为4TB。
每个文件都有一个对应inode结构,通过i_block数组能访问到文件的所以数据,但是inode结构体中没有存储文件名,这是为何?
direntry
实际上文件名保存在目录中,目录也是一个文件,也占用一个inode结构,它的数据块存储的是该目录下所以文件的文件名,以及各个文件对应的inode号。
/*
* Structure of a directory entry
*/
#define EXT4_NAME_LEN 255
struct ext4_dir_entry_2 {
__le32 inode; /* Inode number */
__le16 rec_len; /* Directory entry length */
__u8 name_len; /* Name length */
__u8 file_type;
char name[EXT4_NAME_LEN]; /* File name */
};
inode,存储对应文件的inode号。
name,存储文件名,最大长度255个字节字符。
file_type,存储文件类型,文件类型如下:
/*
* Ext4 directory file types. Only the low 3 bits are used. The
* other bits are reserved for now.
*/
#define EXT4_FT_UNKNOWN 0
#define EXT4_FT_REG_FILE 1
#define EXT4_FT_DIR 2
#define EXT4_FT_CHRDEV 3
#define EXT4_FT_BLKDEV 4
#define EXT4_FT_FIFO 5
#define EXT4_FT_SOCK 6
#define EXT4_FT_SYMLINK 7
#define EXT4_FT_MAX 8
在ext4文件系统中,根目录的inode号固定为2,下面列出特殊的inod号:
/*
* Special inodes numbers
*/
#define EXT4_BAD_INO 1 /* Bad blocks inode */
#define EXT4_ROOT_INO 2 /* Root inode */
#define EXT4_USR_QUOTA_INO 3 /* User quota inode */
#define EXT4_GRP_QUOTA_INO 4 /* Group quota inode */
#define EXT4_BOOT_LOADER_INO 5 /* Boot loader inode */
#define EXT4_UNDEL_DIR_INO 6 /* Undelete directory inode */
#define EXT4_RESIZE_INO 7 /* Reserved group descriptors inode */
#define EXT4_JOURNAL_INO 8 /* Journal inode */
ext4目录项在磁盘上的结构如下图所示:
打印出实际的磁盘目录项结构信息如下图:
每个目录使用direntry保存目录下的文件信息,direntry在磁盘中也是占用一个inode数据结构,inode数据结构中的数据块存储的是该目录下所以文件的文件名,以及各个文件对应的inode号,每个文件的direntry数据信息挨着排列在一个inode中,如上图所示。
定位文件路径位置也是先从direntry开始查找,direntry中保存了文件名信息,如果是多级目录,那么目录文件的inode号又指向下一级目录的direntry的inode。
为什么每级目录下要有.和..两个目录?如果没有这2个目录,那么每次查找文件路径必须从根目录开始查找,这样过于繁琐且效率不高。有了这2个目录,就可以从当前目录出发开始向下一级或者向上一级开始查找,这样效率会高很多。
链接文件
Linux中,为一个文件建立别名称为链接文件。分为软连接和硬链接。
- 硬链接
硬链接文件与原文件的inode号是一致的且相同,没有占用额外的inode空间,硬链接文件通过ls -li查看inode号是一致的,且看不出软连接那样的->符号。
硬链接不能跨越文件系统,因为内核打开硬链接文件只会在当前文件系统中查找对应的inode号,所以即便是2个相同的文件系统之间也不能建立硬链接文件。
- 软连接
又称为符号链接,添加参数-s实现,与原文件的inode号不一致,会占用额外的inode空间,如果文件大于block 4kb * 15 = 60KB的话还会占用额外的数据块了。
软连接可以跨越文件系统。