2021SC@SDUSC
继续分析ext4.h文件
/*超级块的结构*/
struct ext4_super_block {
/*00*/ __le32 s_inodes_count; /* Inodes count */
__le32 s_blocks_count_lo; /* Blocks count */
__le32 s_r_blocks_count_lo; /* 保留块数*/
__le32 s_free_blocks_count_lo; /* 空闲块数*/
/*10*/ __le32 s_free_inodes_count; /* Free inodes count */
__le32 s_first_data_block; /*第一个数据块*/
__le32 s_log_block_size; /*块大小*/
__le32 s_log_cluster_size; /*分配集群大小*/
/*20*/ __le32 s_blocks_per_group; /* #每组的块数*/
__le32 s_clusters_per_group; /* #每组的集群数*/
__le32 s_inodes_per_group; /* # Inodes per group */
__le32 s_mtime; /*挂载时间*/
/*30*/ __le32 s_wtime; /*写入时间*/
__le16 s_mnt_count; /*挂载次数*/
__le16 s_max_mnt_count; /*最大装载计数*/
__le16 s_magic; /*神奇的签名*/
__le16 s_state; /*文件系统状态*/
__le16 s_errors; /*检测错误时的行为*/
__le16 s_minor_rev_level; /*轻微的修订版本*/
/*40*/ __le32 s_lastcheck; /*最后检查时间*/
__le32 s_checkinterval; /* max. time between checks */
__le32 s_creator_os; /* OS */
__le32 s_rev_level; /* Revision level */
/*50*/ __le16 s_def_resuid; /*预留块的默认uid*/
__le16 s_def_resgid; /*保留块的默认gid*/
/*这些字段仅适用于EXT4_DYNAMIC_REV超级块。
需要注意兼容的特性集和不兼容的特性集之间的区别,如果不兼容的特 性集中有一个位集是内核不知道的,它应该拒绝挂载文件系统。
e2fsck的要求更严格;如果它不知道兼容或不兼容特性集中的某个特性, 它必须中止,并且不尝试去干涉它不理解的事情……
*/
__le32 s_first_ino; /* First non-reserved inode */
__le16 s_inode_size; /* size of inode structure */
__le16 s_block_group_nr; /*该超级块的Block group #*/
__le32 s_feature_compat; /*兼容的特性集*/
/*60*/ __le32 s_feature_incompat; /*不兼容的特性集*/
__le32 s_feature_ro_compat; /*只读兼容特性集*/
/*68*/ __u8 s_uuid[16]; /* 128-bit uuid for volume */
/*78*/ char s_volume_name[16]; /* volume name */
/*88*/ char s_last_mounted[64] __nonstring;/*最后挂载的目录*/
/*C8*/ __le32 s_algorithm_usage_bitmap; /* For compression */
/*性能提示。目录预分配应该只在 EXT4_FEATURE_COMPAT_DIR_PREALLOC标志开启的情况下才会发生。
*/
__u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
__u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
__le16 s_reserved_gdt_blocks; /* Per group desc for online growth */
/*
如果EXT4_FEATURE_COMPAT_HAS_JOURNAL设置,那么日志支持有效。 */
/*D0*/ __u8 s_journal_uuid[16]; /*日志超级块的uuid*/
/*E0*/ __le32 s_journal_inum; /*日志文件的inode数 */
__le32 s_journal_dev; /* device number of journal file */
__le32 s_last_orphan; /*要删除的inode列表的开始*/
__le32 s_hash_seed[4]; /* HTREE hash seed */
__u8 s_def_hash_version; /*默认使用的哈希版本*/
__u8 s_jnl_backup_type;
__le16 s_desc_size; /* size of group descriptor */
/*100*/ __le32 s_default_mount_opts;
__le32 s_first_meta_bg; /*第一个元块的块组*/
__le32 s_mkfs_time; /*创建文件系统的时间*/
__le32 s_jnl_blocks[17]; /* Backup of the journal inode */
/* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */
/*150*/ __le32 s_blocks_count_hi; /* Blocks count */
__le32 s_r_blocks_count_hi; /* Reserved blocks count */
__le32 s_free_blocks_count_hi; /* Free blocks count */
__le16 s_min_extra_isize; /*所有索引节点都至少有#字节*/
__le16 s_want_extra_isize; /*新的索引节点应该保留# bytes*/
__le32 s_flags; /* Miscellaneous flags */
__le16 s_raid_stride; /* RAID stride */
__le16 s_mmp_update_interval; /*等待MMP检查#秒数*/
__le64 s_mmp_block; /*多挂载保护块*/
__le32 s_raid_stripe_width; /*所有数据磁盘上的块(N*stride)*/
__u8 s_log_groups_per_flex; /* FLEX_BG group size */
__u8 s_checksum_type; /*使用元数据校验和算法*/
__u8 s_encryption_level; /*加密的版本级别*/
__u8 s_reserved_pad; /*填充到下一个32位*/
__le64 s_kbytes_written; /*写入生命周期的千字节数为Nr*/
__le32 s_snapshot_inum; /*活动快照的Inode个数*/
__le32 s_snapshot_id; /*活动快照的顺序ID*/
__le64 s_snapshot_r_blocks_count; /*为活动快照未来使用的保留块*/
__le32 s_snapshot_list; /*磁盘快照列表头部的Inode号*/
#define EXT4_S_ERR_START offsetof(struct ext4_super_block, s_error_count)
__le32 s_error_count; /* number of fs errors */
__le32 s_first_error_time; /* first time an error happened */
__le32 s_first_error_ino; /*第一个错误涉及的Inode*/
__le64 s_first_error_block; /*第一个错误涉及的块*/
__u8 s_first_error_func[32] __nonstring; /*第一个函数发生错误的地方*/
__le32 s_first_error_line; /* line number where error happened */
__le32 s_last_error_time; /* most recent time of an error */
__le32 s_last_error_ino; /* inode involved in last error */
__le32 s_last_error_line; /* line number where error happened */
__le64 s_last_error_block; /* block involved of last error */
__u8 s_last_error_func[32] __nonstring; /* function where the error happened */
#define EXT4_S_ERR_END offsetof(struct ext4_super_block, s_mount_opts)
__u8 s_mount_opts[64];
__le32 s_usr_quota_inum; /*用于跟踪用户配额的Inode*/
__le32 s_grp_quota_inum; /*用于跟踪组配额的Inode*/
__le32 s_overhead_clusters; /*文件系统中的开销块/集群*/
__le32 s_backup_bgs[2]; /*使用sparse_super2 SBs的组*/
__u8 s_encrypt_algos[4]; /*使用中的加密算法*/
__u8 s_encrypt_pw_salt[16]; /*用于string2key算法的Salt*/
__le32 s_lpf_ino; /* Location of the lost+found inode */
__le32 s_prj_quota_inum; /*用于追踪项目配额的Inode*/
__le32 s_checksum_seed; /*如果csum_seed设置了,用于Crc32c (uuid)*/
__u8 s_wtime_hi;
__u8 s_mtime_hi;
__u8 s_mkfs_time_hi;
__u8 s_lastcheck_hi;
__u8 s_first_error_time_hi;
__u8 s_last_error_time_hi;
__u8 s_first_error_errcode;
__u8 s_last_error_errcode;
__le16 s_encoding; /*文件名字符集编码*/
__le16 s_encoding_flags; /*文件名字符集编码标志*/
__le32 s_orphan_file_inum; /* Inode for tracking orphan inodes */
__le32 s_reserved[94]; /*填充到块的末尾*/
__le32 s_checksum; /* crc32c(superblock) */
};
#define EXT4_S_ERR_LEN (EXT4_S_ERR_END - EXT4_S_ERR_START)
#ifdef __KERNEL__
#ifdef CONFIG_FS_ENCRYPTION
#define DUMMY_ENCRYPTION_ENABLED(sbi) ((sbi)->s_dummy_enc_policy.policy != NULL)
#else
#define DUMMY_ENCRYPTION_ENABLED(sbi) (0)
#endif
/*我们支持的配额类型数量*/
#define EXT4_MAXQUOTAS 3
#define EXT4_ENC_UTF8_12_1 1
/*ext4日志触发器的类型*/
enum ext4_journal_trigger_type {
EXT4_JTR_ORPHAN_FILE,
EXT4_JTR_NONE /*这必须是索引工作的最后一个条目!*/
};
#define EXT4_JOURNAL_TRIGGER_COUNT EXT4_JTR_NONE
struct ext4_journal_trigger {
struct jbd2_buffer_trigger_type tr_triggers;
struct super_block *sb;
};
static inline struct ext4_journal_trigger *EXT4_TRIGGER(
struct jbd2_buffer_trigger_type *trigger)
{
return container_of(trigger, struct ext4_journal_trigger, tr_triggers);
}
#define EXT4_ORPHAN_BLOCK_MAGIC 0x0b10ca04
/*在orphan块的尾部的结构*/
struct ext4_orphan_block_tail {
__le32 ob_magic;
__le32 ob_checksum;
};
static inline int ext4_inodes_per_orphan_block(struct super_block *sb)
{
return (sb->s_blocksize - sizeof(struct ext4_orphan_block_tail)) /
sizeof(u32);
}
struct ext4_orphan_block {
atomic_t ob_free_entries; /*块中自由orphan条目的数量*/
struct buffer_head *ob_bh; /*orphan block 的缓存*/
};
/*orphan文件的信息。*/
struct ext4_orphan_info {
int of_blocks; /*一个文件中orphan块的数量*/
__u32 of_csum_seed; /*orphan文件的校验和种子*/
struct ext4_orphan_block *of_binfo; /*包含orphan文件块信息的数组*/
};
/*内存中的第四代扩展文件系统超级块数据*/
struct ext4_sb_info {
unsigned long s_desc_size; /*以字节为单位组描述符的大小*/
unsigned long s_inodes_per_block;/* Number of inodes per block */
unsigned long s_blocks_per_group;/* Number of blocks in a group */
unsigned long s_clusters_per_group; /* Number of clusters in a group */
unsigned long s_inodes_per_group;/* Number of inodes in a group */
unsigned long s_itb_per_group; /* Number of inode table blocks per group */
unsigned long s_gdb_count; /* Number of group descriptor blocks */
unsigned long s_desc_per_block; /* Number of group descriptors per block */
ext4_group_t s_groups_count; /* Number of groups in the fs */
ext4_group_t s_blockfile_groups;/*可用于非扩展区文件的组*/
unsigned long s_overhead; /*fs开销集群的#*/
unsigned int s_cluster_ratio; /* Number of blocks per cluster */
unsigned int s_cluster_bits; /* log2 of s_cluster_ratio */
loff_t s_bitmap_maxbytes; /* max bytes for bitmap files */
struct buffer_head * s_sbh; /*包含超级块的缓冲区*/
struct ext4_super_block *s_es; /*指向缓冲区中的超级块的指针*/
struct buffer_head * __rcu *s_group_desc;
unsigned int s_mount_opt;
unsigned int s_mount_opt2;
unsigned long s_mount_flags;
unsigned int s_def_mount_opt;
ext4_fsblk_t s_sb_block;
atomic64_t s_resv_clusters;
kuid_t s_resuid;
kgid_t s_resgid;
unsigned short s_mount_state;
unsigned short s_pad;
int s_addr_per_block_bits;
int s_desc_per_block_bits;
int s_inode_size;
int s_first_ino;
unsigned int s_inode_readahead_blks;
unsigned int s_inode_goal;
u32 s_hash_seed[4];
int s_def_hash_version;
int s_hash_unsigned; /*如果哈希值为无符号则为3,否则为0*/
struct percpu_counter s_freeclusters_counter;
struct percpu_counter s_freeinodes_counter;
struct percpu_counter s_dirs_counter;
struct percpu_counter s_dirtyclusters_counter;
struct percpu_counter s_sra_exceeded_retry_limit;
struct blockgroup_lock *s_blockgroup_lock;
struct proc_dir_entry *s_proc;
struct kobject s_kobj;
struct completion s_kobj_unregister;
struct super_block *s_sb;
struct buffer_head *s_mmp_bh;
/*日志记录*/
struct journal_s *s_journal;
unsigned long s_ext4_flags; /* Ext4超级块标志*/
struct mutex s_orphan_lock; /*保护磁盘列表更改*/
struct list_head s_orphan; /*磁盘列表中孤立的索引节点的列表*/
struct ext4_orphan_info s_orphan_info;
unsigned long s_commit_interval;
u32 s_max_batch_time;
u32 s_min_batch_time;
struct block_device *s_journal_bdev;
#ifdef CONFIG_QUOTA
/*具有日志配额的配额文件的名称*/
char __rcu *s_qf_names[EXT4_MAXQUOTAS];
int s_jquota_fmt; /*要使用的配额格式*/
#endif
unsigned int s_want_extra_isize; /*新的索引节点应该保留# bytes*/
struct ext4_system_blocks __rcu *s_system_blks;
#ifdef EXTENTS_STATS
/*ext4区段数据*/
unsigned long s_ext_min;
unsigned long s_ext_max;
unsigned long s_depth_max;
spinlock_t s_ext_stats_lock;
unsigned long s_ext_blocks;
unsigned long s_ext_extents;
#endif
/* for buddy allocator */
struct ext4_group_info ** __rcu *s_group_info;
struct inode *s_buddy_cache;
spinlock_t s_md_lock;
unsigned short *s_mb_offsets;
unsigned int *s_mb_maxs;
unsigned int s_group_info_size;
unsigned int s_mb_free_pending;
struct list_head s_freed_data_list; /*完成提交后要释放的块列表*/
struct list_head s_discard_list;
struct work_struct s_discard_work;
atomic_t s_retry_alloc_pending;
struct rb_root s_mb_avg_fragment_size_root;
rwlock_t s_mb_rb_lock;
struct list_head *s_mb_largest_free_orders;
rwlock_t *s_mb_largest_free_orders_locks;
/*可调参数*/
unsigned long s_stripe;
unsigned int s_mb_max_linear_groups;
unsigned int s_mb_stream_request;
unsigned int s_mb_max_to_scan;
unsigned int s_mb_min_to_scan;
unsigned int s_mb_stats;
unsigned int s_mb_order2_reqs;
unsigned int s_mb_group_prealloc;
unsigned int s_mb_max_inode_prealloc;
unsigned int s_max_dir_size_kb;
/* where last allocation was done - for stream allocation */
unsigned long s_mb_last_group;
unsigned long s_mb_last_start;
unsigned int s_mb_prefetch;
unsigned int s_mb_prefetch_limit;
/*buddy分配程序的统计信息*/
atomic_t s_bal_reqs; /*长度大于1的请求数*/
atomic_t s_bal_success; /*我们找到了足够长的块*/
atomic_t s_bal_allocated; /* in blocks */
atomic_t s_bal_ex_scanned; /*总区段扫描*/
atomic_t s_bal_groups_scanned; /* number of groups scanned */
atomic_t s_bal_goals; /*目标命中*/
atomic_t s_bal_breaks; /* too long searches */
atomic_t s_bal_2orders; /* 2^order hits */
atomic_t s_bal_cr0_bad_suggestions;
atomic_t s_bal_cr1_bad_suggestions;
atomic64_t s_bal_cX_groups_considered[4];
atomic64_t s_bal_cX_hits[4];
atomic64_t s_bal_cX_failed[4]; /*cX循环没有找到块*/
atomic_t s_mb_buddies_generated; /*生成的伙伴数*/
atomic64_t s_mb_generation_time;
atomic_t s_mb_lost_chunks;
atomic_t s_mb_preallocated;
atomic_t s_mb_discarded;
atomic_t s_lock_busy;
/*存储位置分组*/
struct ext4_locality_group __percpu *s_locality_groups;
/*写入统计*/
unsigned long s_sectors_written_start;
u64 s_kbytes_written;
/*零输出块的大小*/
unsigned int s_extent_max_zeroout_kb;
unsigned int s_log_groups_per_flex;
struct flex_groups * __rcu *s_flex_groups;
ext4_group_t s_flex_groups_allocated;
/*用于保留区段转换的工作队列(缓冲io)*/
struct workqueue_struct *rsv_conversion_wq;
/*定时错误统计打印*/
struct timer_list s_err_report;
/*延迟inode表初始化信息*/
struct ext4_li_request *s_li_request;
/*等待乘数来惰性地初始化线程*/
unsigned int s_li_wait_mult;
/*多个挂载保护的内核线程*/
struct task_struct *s_mmp_tsk;
/*记录FITRIM被调用时的最后minlen。*/
atomic_t s_last_trim_minblks;
/*通过cryptoapi引用校验和算法驱动程序*/
struct crypto_shash *s_chksum_driver;
/*预先计算的FS UUID校验和用于其他校验和的种子*/
__u32 s_csum_seed;
/*从区段状态树中回收区段*/
struct shrinker s_es_shrinker;
struct list_head s_es_list; /* List of inodes with reclaimable extents */
long s_es_nr_inode;
struct ext4_es_stats s_es_stats;
struct mb_cache *s_ea_block_cache;
struct mb_cache *s_ea_inode_cache;
spinlock_t s_es_lock ____cacheline_aligned_in_smp;
/*日志触发器用于校验和计算*/
struct ext4_journal_trigger s_journal_triggers[EXT4_JOURNAL_TRIGGER_COUNT];
/*Ratelimit ext4的消息。*/
struct ratelimit_state s_err_ratelimit_state;
struct ratelimit_state s_warning_ratelimit_state;
struct ratelimit_state s_msg_ratelimit_state;
atomic_t s_warning_count;
atomic_t s_msg_count;
/*'-o test_dummy_encryption'的加密策略*/
struct fscrypt_dummy_policy s_dummy_enc_policy;
/*
设置在写页面操作和更改任何inode的JOURNAL_DATA或EXTENTS标 志之间的障碍。
*/
struct percpu_rw_semaphore s_writepages_rwsem;
struct dax_device *s_daxdev;
#ifdef CONFIG_EXT4_DEBUG
unsigned long s_simulate_fail;
#endif
/*记录后端块设备的errseq*/
errseq_t s_bdev_wb_err;
spinlock_t s_bdev_wb_lock;
/*关于此挂载期间发生的错误的信息*/
spinlock_t s_error_lock;
int s_add_error_count;
int s_first_error_code;
__u32 s_first_error_line;
__u32 s_first_error_ino;
__u64 s_first_error_block;
const char *s_first_error_func;
time64_t s_first_error_time;
int s_last_error_code;
__u32 s_last_error_line;
__u32 s_last_error_ino;
__u64 s_last_error_block;
const char *s_last_error_func;
time64_t s_last_error_time;
/*
如果我们无法在磁盘上的超级块中更新错误信息,我们将此工作加入等 待队列,直到它执行结束。
*/
struct work_struct s_error_work;
/* Ext4快速提交的数据*/
atomic_t s_fc_subtid;
atomic_t s_fc_ineligible_updates;
/*
提交开始后,主队列被锁定,进一步的更新被添加到暂存队列中。
*/
#define FC_Q_MAIN 0
#define FC_Q_STAGING 1
struct list_head s_fc_q[2]; /*暂存的索引节点用于快速提交,其中包含数据更改。*/
struct list_head s_fc_dentry_q[2]; /*目录项更新*/
unsigned int s_fc_bytes;
/*
*主要的快速提交锁。这个锁保护对以下字段的访问:
* ei - > i_fc_list, s_fc_dentry_q、s_fc_q s_fc_bytes s_fc_bh。
*/
spinlock_t s_fc_lock;
struct buffer_head *s_fc_bh;
struct ext4_fc_stats s_fc_stats;
u64 s_fc_avg_commit_time;
#ifdef CONFIG_EXT4_DEBUG
int s_fc_debug_max_replay;
#endif
struct ext4_fc_replay_state s_fc_replay_state;
};
/*返回超级块信息*/
static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb)
{
return sb->s_fs_info;
}
/*返回Inode信息*/
static inline struct ext4_inode_info *EXT4_I(struct inode *inode)
{
return container_of(inode, struct ext4_inode_info, vfs_inode);
}
static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
{
return ino == EXT4_ROOT_INO ||
(ino >= EXT4_FIRST_INO(sb) &&
ino <= le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count));
}
/*
* 返回数据: sbi->field[index]
* 用于从下列需要的sbi字段中访问数组元素
* Rcu保护,避免由于重赋值而对无效指针进行解引用
* - s_group_desc
* - s_group_info
* - s_flex_group
*/
#define sbi_array_rcu_deref(sbi, field, index) \
({ \
typeof(*((sbi)->field)) _v; \
rcu_read_lock(); \
_v = ((typeof(_v)*)rcu_dereference((sbi)->field))[index]; \
rcu_read_unlock(); \
_v; \
})
/*
*运行时mount标志
*/
enum {
EXT4_MF_MNTDIR_SAMPLED,
EXT4_MF_FS_ABORTED, /* Fatal error detected */
EXT4_MF_FC_INELIGIBLE, /* Fast commit ineligible */
EXT4_MF_FC_COMMITTING /*正在快速提交的文件系统。*/
};
static inline void ext4_set_mount_flag(struct super_block *sb, int bit)
{
set_bit(bit, &EXT4_SB(sb)->s_mount_flags);
}
static inline void ext4_clear_mount_flag(struct super_block *sb, int bit)
{
clear_bit(bit, &EXT4_SB(sb)->s_mount_flags);
}
static inline int ext4_test_mount_flag(struct super_block *sb, int bit)
{
return test_bit(bit, &EXT4_SB(sb)->s_mount_flags);
}
/*
* Simulate_fail代码
*/
#define EXT4_SIM_BBITMAP_EIO 1
#define EXT4_SIM_BBITMAP_CRC 2
#define EXT4_SIM_IBITMAP_EIO 3
#define EXT4_SIM_IBITMAP_CRC 4
#define EXT4_SIM_INODE_EIO 5
#define EXT4_SIM_INODE_CRC 6
#define EXT4_SIM_DIRBLOCK_EIO 7
#define EXT4_SIM_DIRBLOCK_CRC 8
static inline bool ext4_simulate_fail(struct super_block *sb,
unsigned long code)
{
#ifdef CONFIG_EXT4_DEBUG
struct ext4_sb_info *sbi = EXT4_SB(sb);
if (unlikely(sbi->s_simulate_fail == code)) {
sbi->s_simulate_fail = 0;
return true;
}
#endif
return false;
}
static inline void ext4_simulate_fail_bh(struct super_block *sb,
struct buffer_head *bh,
unsigned long code)
{
if (!IS_ERR(bh) && ext4_simulate_fail(sb, code))
clear_buffer_uptodate(bh);
}
/*
* 错误码s_{第一个,最后一个}_error_errno修改翻译结果
*Linux errno数字是特定于体系结构的,因此我们需要将它们转换为与体系结*构无关的东西。我们没有为所有的errno定义代码;只是那些最有可能是*ext4_error()调用的原因。
*
*/
#define EXT4_ERR_UNKNOWN 1
#define EXT4_ERR_EIO 2
#define EXT4_ERR_ENOMEM 3
#define EXT4_ERR_EFSBADCRC 4
#define EXT4_ERR_EFSCORRUPTED 5
#define EXT4_ERR_ENOSPC 6
#define EXT4_ERR_ENOKEY 7
#define EXT4_ERR_EROFS 8
#define EXT4_ERR_EFBIG 9
#define EXT4_ERR_EEXIST 10
#define EXT4_ERR_ERANGE 11
#define EXT4_ERR_EOVERFLOW 12
#define EXT4_ERR_EBUSY 13
#define EXT4_ERR_ENOTDIR 14
#define EXT4_ERR_ENOTEMPTY 15
#define EXT4_ERR_ESHUTDOWN 16
#define EXT4_ERR_EFAULT 17
/* Inode动态状态标志*/
enum {
EXT4_STATE_JDATA, /* journaled data exists */
EXT4_STATE_NEW, /* inode is newly created */
EXT4_STATE_