EXT4檔案系統學習(9)VFS之磁碟結構inode和direntry

王二車發表於2019-02-13

核心版本: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的話還會佔用額外的資料塊了。

軟連線可以跨越檔案系統。

 

相關文章