2021SC@SDUSC
今天来分析ext4_extents.h 、 xattr.h 、 truncate.h 三个头文件,为以后分析inode.c核心文件打下基础。
以下是ext4_extents.h头文件的代码分析
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2003-2006, Cluster File Systems, Inc, info@clusterfs.com
* Written by Alex Tomas <alex@clusterfs.com>
*/
#ifndef _EXT4_EXTENTS
#define _EXT4_EXTENTS
#include "ext4.h"
/*随着aggressive ve_test的定义,索引/叶块的容量变得非常小,因此索引分裂、深度增长和其他硬变化发生得更频繁。这仅用于调试目的。*/
#define AGGRESSIVE_TEST_
/*定义EXTENTS_STATS后,在截断路径中收集块和区段的数量。它们将在umount时间显示。*/
#define EXTENTS_STATS__
/*如果定义了CHECK_BINSEARCH,那么二进制搜索的结果也将通过线性搜索进行检查。*/
#define CHECK_BINSEARCH__
/*如果定义了EXT_STATS,则统计数据将被收集。这些数字将在umount时显示。*/
#define EXT_STATS_
/** ext4_inode有i_block数组(总共60字节)。
*前12字节存储ext4_extent_header;其余存储ext4_extent数组。对于非inode扩展块,ext4_extent_tail紧跟在数组之后。*/
/**这是磁盘上的extent tail结构。
*所有其他区段结构都是12字节长。结果表明,对于大于512的2的所有幂,block_size % 12 >= 4,这覆盖了所有有效的ext4块大小。因此,这个尾部结构可以被塞到块的末端,而不需要重新平衡树。*/
struct ext4_extent_tail {
__le32 et_checksum; /* crc32c(uuid+inum+extent_block) */
};
/*这是磁盘上的extent结构。
它在树的底部使用。*/
struct ext4_extent {
__le32 ee_block; /* 首先逻辑块范围覆盖*/
__le16 ee_len; /* 范围所覆盖的块数*/
__le16 ee_start_hi; /* 高16位的物理块*/
__le32 ee_start_lo; /* 低32位物理块*/
};
/*这是磁盘索引结构。
除底部外,所有级别都使用。*/
struct ext4_extent_idx {
__le32 ei_block; /* 索引涵盖了来自“block”的逻辑块*/
__le32 ei_leaf_lo; /*指针指向下一层的物理块。叶索引或下一个索引可能在那里*/
__le16 ei_leaf_hi; /*高16位的物理块 */
__u16 ei_unused;
};
/*每个块(叶子和索引),即使是inode存储的也有头。*/
struct ext4_extent_header {
__le16 eh_magic; /* 可能会支持不同的格式*/
__le16 eh_entries; /* 有效条目数量*/
__le16 eh_max; /* 入库容量*/
__le16 eh_depth; /*树有真正的底层块吗? */
__le32 eh_generation; /* 树的各代*/
};
#define EXT4_EXT_MAGIC cpu_to_le16(0xf30a)
#define EXT4_MAX_EXTENT_DEPTH 5
#define EXT4_EXTENT_TAIL_OFFSET(hdr) \
(sizeof(struct ext4_extent_header) + \
(sizeof(struct ext4_extent) * le16_to_cpu((hdr)->eh_max)))
static inline struct ext4_extent_tail *
find_ext4_extent_tail(struct ext4_extent_header *eh)
{
return (struct ext4_extent_tail *)(((void *)eh) +
EXT4_EXTENT_TAIL_OFFSET(eh));
}
/*ext4_ext_path数组中包含路径。
*创建/查找例程使用它来遍历/分割/等。
* Truncate使用它来模拟递归遍历。
*/
struct ext4_ext_path {
ext4_fsblk_t p_block;
__u16 p_depth;
__u16 p_maxdepth;
struct ext4_extent *p_ext;
struct ext4_extent_idx *p_idx;
struct ext4_extent_header *p_hdr;
struct buffer_head *p_bh;
};
/**用于在空间移除期间遍历区段树时,记录在区段开始或结束时发现的簇的一部分。
*如果一个部分集群中没有与未被删除的区段共享的块(处于空闲状态),可能会被移除。否则,它不能被删除(nofree状态)。*/
struct partial_cluster {
ext4_fsblk_t pclu; /* physical cluster number */
ext4_lblk_t lblk; /* logical block number within logical cluster */
enum {initial, tofree, nofree} state;
};
/**结构的外部API*/
/** EXT_INIT_MAX_LEN是在初始化的extent中可以拥有的最大块数。这是2^15而不是(2^16 - 1),因为我们在区段数据结构中使用ee_len字段的MSB来表示这个特定的区段是初始化的还是未写入的(即预分配的)。
* EXT_UNWRITTEN_MAX_LEN是一个未写入区可以拥有的最大块数。如果ee_len <= 0x8000,则它是一个初始化的范围。否则,它是一个不成文的。换句话说,如果设置了ee_len的MSB,则它是一个未写入区,只有一个特殊场景:ee_len = 0x8000。在本例中,我们不能有长度为0的未写入范围,因此我们将其作为长度为0x8000的初始化范围的特殊情况。
*通过这种方式,我们可以更好地对初始化的区段和组进行对齐。
因此,在一个*初始化的*区段中我们可以拥有的最大块数是2^15(32768),而在一个*未写入的*区段中我们可以拥有的最大块数是2^15-1(32767)。
*/
#define EXT_INIT_MAX_LEN (1UL << 15)
#define EXT_UNWRITTEN_MAX_LEN (EXT_INIT_MAX_LEN - 1)
#define EXT_FIRST_EXTENT(__hdr__) \
((struct ext4_extent *) (((char *) (__hdr__)) + \
sizeof(struct ext4_extent_header)))
#define EXT_FIRST_INDEX(__hdr__) \
((struct ext4_extent_idx *) (((char *) (__hdr__)) + \
sizeof(struct ext4_extent_header)))
#define EXT_HAS_FREE_INDEX(__path__) \
(le16_to_cpu((__path__)->p_hdr->eh_entries) \
< le16_to_cpu((__path__)->p_hdr->eh_max))
#define EXT_LAST_EXTENT(__hdr__) \
(EXT_FIRST_EXTENT((__hdr__)) + le16_to_cpu((__hdr__)->eh_entries) - 1)
#define EXT_LAST_INDEX(__hdr__) \
(EXT_FIRST_INDEX((__hdr__)) + le16_to_cpu((__hdr__)->eh_entries) - 1)
#define EXT_MAX_EXTENT(__hdr__) \
((le16_to_cpu((__hdr__)->eh_max)) ? \
((EXT_FIRST_EXTENT((__hdr__)) + le16_to_cpu((__hdr__)->eh_max) - 1)) \
: 0)
#define EXT_MAX_INDEX(__hdr__) \
((le16_to_cpu((__hdr__)->eh_max)) ? \
((EXT_FIRST_INDEX((__hdr__)) + le16_to_cpu((__hdr__)->eh_max) - 1)) : 0)
static inline struct ext4_extent_header *ext_inode_hdr(struct inode *inode)
{
return (struct ext4_extent_header *) EXT4_I(inode)->i_data;
}
static inline struct ext4_extent_header *ext_block_hdr(struct buffer_head *bh)
{
return (struct ext4_extent_header *) bh->b_data;
}
static inline unsigned short ext_depth(struct inode *inode)
{
return le16_to_cpu(ext_inode_hdr(inode)->eh_depth);
}
static inline void ext4_ext_mark_unwritten(struct ext4_extent *ext)
{
/* We can not have an unwritten extent of zero length! */
BUG_ON((le16_to_cpu(ext->ee_len) & ~EXT_INIT_MAX_LEN) == 0);
ext->ee_len |= cpu_to_le16(EXT_INIT_MAX_LEN);
}
static inline int ext4_ext_is_unwritten(struct ext4_extent *ext)
{
/* Extent with ee_len of 0x8000 is treated as an initialized extent */
return (le16_to_cpu(ext->ee_len) > EXT_INIT_MAX_LEN);
}
static inline int ext4_ext_get_actual_len(struct ext4_extent *ext)
{
return (le16_to_cpu(ext->ee_len) <= EXT_INIT_MAX_LEN ?
le16_to_cpu(ext->ee_len) :
(le16_to_cpu(ext->ee_len) - EXT_INIT_MAX_LEN));
}
static inline void ext4_ext_mark_initialized(struct ext4_extent *ext)
{
ext->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ext));
}
/** ext4_ext_pblock:
*将物理块号的高低部分合并成ext4_fsblk_t
*/
static inline ext4_fsblk_t ext4_ext_pblock(struct ext4_extent *ex)
{
ext4_fsblk_t block;
block = le32_to_cpu(ex->ee_start_lo);
block |= ((ext4_fsblk_t) le16_to_cpu(ex->ee_start_hi) << 31) << 1;
return block;
}
/** ext4_idx_pblock:
将叶子物理块号的高低部分合并到ext4_fsblk_t中
*/
static inline ext4_fsblk_t ext4_idx_pblock(struct ext4_extent_idx *ix)
{
ext4_fsblk_t block;
block = le32_to_cpu(ix->ei_leaf_lo);
block |= ((ext4_fsblk_t) le16_to_cpu(ix->ei_leaf_hi) << 31) << 1;
return block;
}
/** ext4_ext_store_pblock:
*将一个大的物理块数存储到一个区段结构中,并将其分解为多个部分
*/
static inline void ext4_ext_store_pblock(struct ext4_extent *ex,
ext4_fsblk_t pb)
{
ex->ee_start_lo = cpu_to_le32((unsigned long) (pb & 0xffffffff));
ex->ee_start_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) &
0xffff);
}
/* ext4_idx_store_pblock:
*将一个大的物理块数存储到一个索引结构中,并将其分解为多个部分*/
static inline void ext4_idx_store_pblock(struct ext4_extent_idx *ix,
ext4_fsblk_t pb)
{
ix->ei_leaf_lo = cpu_to_le32((unsigned long) (pb & 0xffffffff));
ix->ei_leaf_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) &
0xffff);
}
#endif /* _EXT4_EXTENTS */
以下是xattr.h头文件的代码分析
// SPDX-License-Identifier: GPL-2.0
/*
File: fs/ext4/xattr.h
On-disk format of extended attributes for the ext4 filesystem.
(C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org>
*/
#include <linux/xattr.h>
/* 属性块中的魔法值 */
#define EXT4_XATTR_MAGIC 0xEA020000
/* 对一个属性块的最大引用数 */
#define EXT4_XATTR_REFCOUNT_MAX 1024
/* 名称索引*/
#define EXT4_XATTR_INDEX_USER 1
#define EXT4_XATTR_INDEX_POSIX_ACL_ACCESS 2
#define EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT 3
#define EXT4_XATTR_INDEX_TRUSTED 4
#define EXT4_XATTR_INDEX_LUSTRE 5
#define EXT4_XATTR_INDEX_SECURITY 6
#define EXT4_XATTR_INDEX_SYSTEM 7
#define EXT4_XATTR_INDEX_RICHACL 8
#define EXT4_XATTR_INDEX_ENCRYPTION 9
#define EXT4_XATTR_INDEX_HURD 10 /* 预留给HURD */
struct ext4_xattr_header {
__le32 h_magic; /* 用于标识的魔数 */
__le32 h_refcount; /* 引用计数 */
__le32 h_blocks; /* 已使用的磁盘块数 */
__le32 h_hash; /* 所有属性的哈希值 */
__le32 h_checksum; /* crc32c(uuid+id+xattrblock) */
/* 如果refcount=1, Id = inum,否则为blknum */
__u32 h_reserved[3];
};
struct ext4_xattr_ibody_header {
__le32 h_magic; /* 用于标识的魔数 */
};
struct ext4_xattr_entry {
__u8 e_name_len; /* 名字的长度 */
__u8 e_name_index; /* 属性名称索引 */
__le16 e_value_offs; /* 磁盘块中的偏移值 */
__le32 e_value_inum; /* 存储值的索引节点 */
__le32 e_value_size; /* 属性值大小 */
__le32 e_hash; /* name和value的散列值 */
char e_name[]; /* 属性名称 */
};
#define EXT4_XATTR_PAD_BITS 2
#define EXT4_XATTR_PAD (1<<EXT4_XATTR_PAD_BITS)
#define EXT4_XATTR_ROUND (EXT4_XATTR_PAD-1)
#define EXT4_XATTR_LEN(name_len) \
(((name_len) + EXT4_XATTR_ROUND + \
sizeof(struct ext4_xattr_entry)) & ~EXT4_XATTR_ROUND)
#define EXT4_XATTR_NEXT(entry) \
((struct ext4_xattr_entry *)( \
(char *)(entry) + EXT4_XATTR_LEN((entry)->e_name_len)))
#define EXT4_XATTR_SIZE(size) \
(((size) + EXT4_XATTR_ROUND) & ~EXT4_XATTR_ROUND)
#define IHDR(inode, raw_inode) \
((struct ext4_xattr_ibody_header *) \
((void *)raw_inode + \
EXT4_GOOD_OLD_INODE_SIZE + \
EXT4_I(inode)->i_extra_isize))
#define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1))
/*
XATTR_SIZE_MAX目前是64k,但是为了检查文件系统一致性错误,我们使用了一个更大的值。
这允许XATTR_SIZE_MAX在未来增长,但是在某些一致性检查中使用它而不是INT_MAX,我们不需要担心算术溢出。
(实际上XATTR_SIZE_MAX是在include/uapi/linux/limits.h中定义的,所以改变它不会是简单的....)
*/
#define EXT4_XATTR_SIZE_MAX (1 << 24)
/*
当您开始将EA值存储在外部索引节点时,
它的最小大小为块大小-头大小- 1个条目大小- 4个空字节
*/
#define EXT4_XATTR_MIN_LARGE_EA_SIZE(b) \
((b) - EXT4_XATTR_LEN(3) - sizeof(struct ext4_xattr_header) - 4)
#define BHDR(bh) ((struct ext4_xattr_header *)((bh)->b_data))
#define ENTRY(ptr) ((struct ext4_xattr_entry *)(ptr))
#define BFIRST(bh) ENTRY(BHDR(bh)+1)
#define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0)
#define EXT4_ZERO_XATTR_VALUE ((void *)-1)
struct ext4_xattr_info {
const char *name;
const void *value;
size_t value_len;
int name_index;
int in_inode;
};
struct ext4_xattr_search {
struct ext4_xattr_entry *first;
void *base;
void *end;
struct ext4_xattr_entry *here;
int not_found;
};
struct ext4_xattr_ibody_find {
struct ext4_xattr_search s;
struct ext4_iloc iloc;
};
struct ext4_xattr_inode_array {
unsigned int count; /* 数组中使用的条目的# */
struct inode *inodes[];
};
extern const struct xattr_handler ext4_xattr_user_handler;
extern const struct xattr_handler ext4_xattr_trusted_handler;
extern const struct xattr_handler ext4_xattr_security_handler;
extern const struct xattr_handler ext4_xattr_hurd_handler;
#define EXT4_XATTR_NAME_ENCRYPTION_CONTEXT "c"
/*
EXT4_STATE_NO_EXPAND是重载的,用于两个目的。
第一个是发出信号,表示内联xattrs和数据占用了太多的空间,所以我们最好不要一直尝试扩展它。
其次,xattr_sem用于写入,因此不应该尝试递归到inode展开中。
对于第二种情况,我们需要确保适当地使用保存和恢复NO_EXPAND状态标志。
*/
static inline void ext4_write_lock_xattr(struct inode *inode, int *save)
{
down_write(&EXT4_I(inode)->xattr_sem);
*save = ext4_test_inode_state(inode, EXT4_STATE_NO_EXPAND);
ext4_set_inode_state(inode, EXT4_STATE_NO_EXPAND);
}
static inline int ext4_write_trylock_xattr(struct inode *inode, int *save)
{
if (down_write_trylock(&EXT4_I(inode)->xattr_sem) == 0)
return 0;
*save = ext4_test_inode_state(inode, EXT4_STATE_NO_EXPAND);
ext4_set_inode_state(inode, EXT4_STATE_NO_EXPAND);
return 1;
}
static inline void ext4_write_unlock_xattr(struct inode *inode, int *save)
{
if (*save == 0)
ext4_clear_inode_state(inode, EXT4_STATE_NO_EXPAND);
up_write(&EXT4_I(inode)->xattr_sem);
}
extern ssize_t ext4_listxattr(struct dentry *, char *, size_t);
extern int ext4_xattr_get(struct inode *, int, const char *, void *, size_t);
extern int ext4_xattr_set(struct inode *, int, const char *, const void *, size_t, int);
extern int ext4_xattr_set_handle(handle_t *, struct inode *, int, const char *, const void *, size_t, int);
extern int ext4_xattr_set_credits(struct inode *inode, size_t value_len,
bool is_create, int *credits);
extern int __ext4_xattr_set_credits(struct super_block *sb, struct inode *inode,
struct buffer_head *block_bh, size_t value_len,
bool is_create);
extern int ext4_xattr_delete_inode(handle_t *handle, struct inode *inode,
struct ext4_xattr_inode_array **array,
int extra_credits);
extern void ext4_xattr_inode_array_free(struct ext4_xattr_inode_array *array);
extern int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
struct ext4_inode *raw_inode, handle_t *handle);
extern const struct xattr_handler *ext4_xattr_handlers[];
extern int ext4_xattr_ibody_find(struct inode *inode, struct ext4_xattr_info *i,
struct ext4_xattr_ibody_find *is);
extern int ext4_xattr_ibody_get(struct inode *inode, int name_index,
const char *name,
void *buffer, size_t buffer_size);
extern int ext4_xattr_ibody_set(handle_t *handle, struct inode *inode,
struct ext4_xattr_info *i,
struct ext4_xattr_ibody_find *is);
extern struct mb_cache *ext4_xattr_create_cache(void);
extern void ext4_xattr_destroy_cache(struct mb_cache *);
#ifdef CONFIG_EXT4_FS_SECURITY
extern int ext4_init_security(handle_t *handle, struct inode *inode,
struct inode *dir, const struct qstr *qstr);
#else
static inline int ext4_init_security(handle_t *handle, struct inode *inode,
struct inode *dir, const struct qstr *qstr)
{
return 0;
}
#endif
#ifdef CONFIG_LOCKDEP
extern void ext4_xattr_inode_set_class(struct inode *ea_inode);
#else
static inline void ext4_xattr_inode_set_class(struct inode *ea_inode) { }
#endif
extern int ext4_get_inode_usage(struct inode *inode, qsize_t *usage);
以下是truncate.h头文件的代码分析:
// SPDX-License-Identifier: GPL-2.0
/*
* linux/fs/ext4/truncate.h
*
* Common inline functions needed for truncate support
*/
/*
截断未被写入使用的块。
我们还必须截断页面缓存,以便正确地取消相应的缓冲区映射。
*/
static inline void ext4_truncate_failed_write(struct inode *inode)
{
/*
我们不需要调用ext4_break_layouts(),
因为我们正在截断的块对用户空间是不可见的。
*/
down_write(&EXT4_I(inode)->i_mmap_sem);
truncate_inode_pages(inode->i_mapping, inode->i_size);
ext4_truncate(inode);
up_write(&EXT4_I(inode)->i_mmap_sem);
}
/*
计算出我们需要多少块来处理截断事务的下一个块。
*/
static inline unsigned long ext4_blocks_for_truncate(struct inode *inode)
{
ext4_lblk_t needed;
needed = inode->i_blocks >> (inode->i_sb->s_blocksize_bits - 9);
/*
给我们足够的空间来处理i_blocks损坏的inode:
我们在过去看到过磁盘损坏导致inode中出现随机数据,
这些数据看起来很像ext4试图删除的常规文件。
如果发生这种情况,事情会变得有点疯狂,
但至少我们应该尽量不要让整个内核感到恐慌。
*/
if (needed < 2)
needed = 2;
/*
我们需要对事务进行约束,以避免日记账溢出。
*/
if (needed > EXT4_MAX_TRANS_DATA)
needed = EXT4_MAX_TRANS_DATA;
return EXT4_DATA_TRANS_BLOCKS(inode->i_sb) + needed;
|