1 file_system_type
cpp
// <fs.h>
struct file_system_type {
const char *name;
int fs_flags;
struct super_block *(*get_sb) (struct file_system_type *, int,
const char *, void *, struct vfsmount *);
void (*kill_sb) (struct super_block *);
struct module *owner;
struct file_system_type * next;
struct list_head fs_supers;
};
1.1 file_system_type相关的链表
(1)struct file_system_type * next;
各个可用的文件系统通过next成员连接起来,这里无法利用标准的链表功能,因为这是一个单链表。
1.2 几个重要的成员变量说明
我们最感兴趣的成员是fs_supers和函数指针get_sb。对于每个已经装载的文件系统,在内存中都创建了一个超级块结构。该结构保存了文件系统它本身和装载点的有关信息。由于可以装载几个同一类型的文件系统(最好的例子是home和root分区,二者的文件系统类型通常相同),同一文件系统类型可能对应了多个超级块结构,这些超级块聚集在一个链表中。fs_supers是对应的表头。
2 vfsmount
cpp
// <mount.h>
struct vfsmount {
struct list_head mnt_hash;
struct vfsmount *mnt_parent; /* 装载点所在的父文件系统 */
struct dentry *mnt_mountpoint; /* 装载点在父文件系统中的dentry */
struct dentry *mnt_root; /* 当前文件系统根目录的dentry */
struct super_block *mnt_sb; /* 指向超级块的指针 */
struct list_head mnt_mounts; /* 子文件系统链表 */
struct list_head mnt_child; /* 链表元素,用于父文件系统中的mnt_mounts链表 */
int mnt_flags;
/* 64位体系结构上,是一个4字节的空洞 */
char *mnt_devname; /* 设备名称,例如/dev/dsk/hda1 */
struct list_head mnt_list;
struct list_head mnt_expire; /* 链表元素,用于特定于文件系统的到期链表中 */
struct list_head mnt_share; /* 链表元素,用于共享装载的循环链表 */
struct list_head mnt_slave_list;/* 从属装载的链表 */
struct list_head mnt_slave; /* 链表元素,用于从属装载的链表 */
struct vfsmount *mnt_master; /* 指向主装载,从属装载位于master->mnt_slave_list链表上 */
struct mnt_namespace *mnt_ns; /* 所属的命名空间 */
/*
* 我们把mnt_count和mnt_expiry_mark放置在struct vfsmount的末尾,
* 以便让这些频繁修改的字段与结构的主体处于两个不同的缓存行中
* (这样在SMP机器上读取mnt_flags不会造成高速缓存的颠簸)
*/
atomic_t mnt_count;
int mnt_expiry_mark; /* 如果标记为到期,则其值为true */
};
2.1 几个重要的成员变量说明
(1)struct vfsmount *mnt_parent;
装载点所在的父文件系统的vfsmount实例
(2)struct dentry *mnt_mountpoint;
装载点所在的父文件系统的dentry实例
(3)struct dentry *mnt_root;
当前文件系统根目录的dentry实例
2.2 相关的链表
2.2.1 相关成员变量
cpp
struct vfsmount *mnt_parent; /* 装载点所在的父文件系统 */
struct list_head mnt_mounts; /* 子文件系统链表 */
struct list_head mnt_child; /* 链表元素,用于父文件系统中的mnt_mounts链表 */
2.2.2 链表关系图示
3 super_block
cpp
// <fs.h>
struct super_block {
struct list_head s_list; /* 将该成员置于起始处 */
dev_t s_dev; /* 搜索索引,不是kdev_t */
unsigned long s_blocksize;
unsigned char s_blocksize_bits;
unsigned char s_dirt;
unsigned long long s_maxbytes; /* 最大的文件长度 */
struct file_system_type *s_type;
struct super_operations *s_op;
unsigned long s_flags;
unsigned long s_magic;
struct dentry *s_root;
struct xattr_handler **s_xattr;
struct list_head s_inodes; /* 所有inode的链表 */
struct list_head s_dirty; /* 脏inode的链表 */
struct list_head s_io; /* 等待回写 */
struct list_head s_more_io; /* 等待回写,另一个链表 */
struct list_head s_files;
struct block_device *s_bdev;
struct list_head s_instances;
char s_id[32]; /* 有意义的名字 */
void *s_fs_info; /* 文件系统私有信息 */
/* 创建/修改/访问时间的粒度,单位为ns(纳秒)。粒度不能大于1秒 */
u32 s_time_gran;
};
3.1 几个重要的成员变量说明
(1)struct list_head s_files;
s_files链表包含了一系列file结构,列出了该超级块表示的文件系统上所有打开的文件。内核在卸载文件系统时将参考该链表。
3.2 super_block相关的链表
结构的第一个成员s_list是一个链表元素,用于将系统中所有的超级块聚集到一个链表中。该 链表的表头是全程变量super_blocks,定义在fs/super.c中。 最后,各个超级块都连接到另一个链表中,表示同一类型文件系统的所有超级块实例,这里不考 虑底层的块设备,但链表中的超级块的文件系统类型都是相同的。表头是file_system_type结构的 fs_supers成员,s_instances用作链表元素。
4 inode
cpp
// <fs.h>
struct inode {
struct hlist_node i_hash;
struct list_head i_list;
struct list_head i_sb_list;
struct list_head i_dentry;
unsigned long i_ino;
atomic_t i_count;
unsigned int i_nlink;
uid_t i_uid;
gid_t i_gid;
dev_t i_rdev;
unsigned long i_version;
loff_t i_size;
struct timespec i_atime;
struct timespec i_mtime;
struct timespec i_ctime;
unsigned int i_blkbits;
blkcnt_t i_blocks;
umode_t i_mode;
struct inode_operations *i_op;
const struct file_operations *i_fop; /* 此前为->i_op->default_file_ops */
struct super_block *i_sb;
struct address_space *i_mapping;
struct address_space i_data;
struct dquot *i_dquot[MAXQUOTAS];
struct list_head i_devices;
union {
struct pipe_inode_info *i_pipe;
struct block_device *i_bdev;
struct cdev *i_cdev;
};
int i_cindex;
__u32 i_generation;
unsigned long i_state;
unsigned long dirtied_when; /* 第一个脏操作发生的时间,以jiffies计算 */
unsigned int i_flags;
atomic_t i_writecount;
void *i_security;
};
4.1 inode相关的链表
(1)struct list_head i_devices;
利用该成员作为链表元素,使得块设备或字符设备可以维护一个inode的链表,每个inode表示一个设备文件,通过设备文件可以访问对应的设备。
(2)struct list_head i_list;
可以将inode通过i_list成员存储在一个链表中,根据inode的状态,它有3种主要的情况。
① 全局变量inode_unused用作表头,该链表管理有效但非活动的inode。
② 全局变量inode_in_use用作表头,该链表管理所有使用但未改变的inode。
③ super_block中的s_dirty成员变量用作表头,该链表管理所有脏的inode。
④ 无效inode保存在一个本地链表中。(在检测到可移动设备的介质改变时,此前使用的inode就都没有意义了,另外文件系统重新装载时也会发生这种情况。)
(3)struct list_head i_sb_list;
super_block中的s_inodes成员变量用作表头,该链表管理所有打开的inode。
4.2 inode相关的哈希散列表
(1)每个inode不仅出现在特定于状态的链表中,还在一个散列表中出现,以支持根据inode编号和超级块快速访问inode,这两项的组合在系统范围内是唯一的。该散列表是一个数组,全局变量inode_hashtable是存储inode的哈希表。
(2)fs/inode.c中的hash函数用于计算散列和。它将inode编号和超级块对象的地址合并为一个唯一的编号,保证位于散列表已经分配的下标范围内。碰撞照例通过溢出链表解决。inode的成员i_hash用于管理溢出链表。
5 dentry
cpp
// <dcache.h>
struct dentry {
atomic_t d_count;
unsigned int d_flags; /* 由d_lock保护 */
spinlock_t d_lock; /* 每个dentry的锁 */
struct inode *d_inode; /* 文件名所属的inode,如果为NULL,则表示不存在的文件名 */
/*
* 接下来的3个字段由__d_lookup处理
* 将它们放置在这里,使之能够装填到一个缓存行中
*/
struct hlist_node d_hash; /* 用于查找的散列表 */
struct dentry *d_parent; /* 父目录的dentry实例 */
struct qstr d_name;
struct list_head d_lru; /* LRU链表 */
union {
struct list_head d_child;
/* 链表元素,用于将当前dentry连接到父目录dentry的d_subdirs链表中 */
struct rcu_head d_rcu;
} d_u;
struct list_head d_subdirs; /* 子目录/文件的目录项链表 */
struct list_head d_alias; /* 链表元素,用于将dentry连接到inode的i_dentry链表中 */
unsigned long d_time; /* 由d_revalidate使用 */
struct dentry_operations *d_op;
struct super_block *d_sb; /* dentry树的根,超级块 */
void *d_fsdata; /* 特定于文件系统的数据 */
int d_mounted;
unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* 短文件名存储在这里 */
};
5.1 几个重要的成员变量说明
(1)dentry中的d_mounted
如果当前dentry对象表示一个装载点,那么d_mounted设置为1;否则其值为0。
5.2 dentry缓存
在VFS连同文件系统实现读取的一个目录项(目录或文件)的数据之后,则创建一个dentry实例,以缓存找到的数据。dentry缓存是如何组织的?dentry对象在内存中的组织,涉及下面两个部分:
- 一个散列表(dentry_hashtable)包含了所有的dentry对象。
- 一个LRU(最近最少使用,least recently used)链表,其中不再使用的对象将授予一个最后宽限期,宽限期过后才从内存移除。
5.2.1 dentry缓存相关的哈希散列表
内存中所有活动的dentry实例都保存在一个散列表中,该散列表使用fs/dcache.c中的全局变量dentry_hashtable实现。fs/dcache.c中的d_hash函数用于确定dentry对象的散列位置。
5.2.2 dentry缓存相关的链表
(1)struct list_head d_lru;
全局变量dentry_unused用作表头,该链表管理最近最少使用的dentry。
5.3 dentry相关的链表
5.3.1 相关成员变量
cpp
struct dentry *d_parent; /* 父目录的dentry实例 */
struct list_head d_subdirs; /* 子目录/文件的目录项链表 */
struct list_head d_child; /* 链表元素,用于将当前dentry连接到父目录dentry的d_subdirs链表中 */