目录
8.3 VFS结构
8.3.1 结构概观
8.3.2 inode
本专栏文章将有70篇左右,欢迎+关注,查看后续文章。
8.3 VFS结构
8.3.1 结构概观
VFS组成部分:
1. 文件。
2. 文件系统。
1. 文件的表示
inode:包含文件信息及数据存储位置。
上图右下方:
struct files_struct { //作用:跟踪该进程所有打开的文件。
struct file *fd_array[ NR_OPEN_DEFAULT ]; // fd 作为索引
};
struct dentry:表示一个目录项。
作用:缓存文件路径名。加速文件查找和访问。
底层的操作函数指针:
1. struct inode_operations 包括:
创建链接,文件重命名,创建文件,删除文件。
2. struct file_operations 包括:
读写文件,mmap,设置文件位置等指针。
2. 文件系统和超级块信息
超级块:struct super_block
struct super_block 包含:
1. 文件系统信息:块长度,最大文件长度。
2. 修改过的 inode 列表。
3. 通过 struct super_operations *s_op 包括操作 inode 的函数指针,如:
alloc_inode,write_inode,destroy_inode,dirty_inode,remount_fs 等。
8.3.2 inode
inode 分为:
存在磁盘中:存在于底层的具体文件系统中。
存在内存中:即 struct inode(本节所讲)。
从磁盘中读取到的 inode 信息,将填充到内存 struct inode。
应用层访问文件的过程:
1. 路径解析。寻找对应 dentry,若未找到则创建dentry。
2. 通过 dentry 找到对应 inode。
3. 分配 fd 和 struct file 对象。
从Ext2开始,内核将文件属性和文件内容分开存储,分别对应 inode 和数据块 block。
struct inode {
umode_t i_mode;
// 10位,1位是文件类型,后9位是所有者/组/其他成员的读写访问权限。
kuid_t i_uid; // 使用者 id
kgid_t i_gid; // 所属组
unsigned int i_flags;
struct inode_operations *i_op;
struct super_block *i_sb;
struct address_space *i_mapping; // 通常指向 i_data
unsigned long i_ino;
//索引节点号,每个 inode 唯一,根目录的 i_ino 通常为0。
union {
const unsigned int i_nlink; // 硬链接数目。
unsigned int __i_nlink;
};
dev_t i_rdev; // 当为设备文件时,表示设备号。
loff_t i_size; // 文件的长度,单位字节。
struct timespec64 i_atime; // 最后访问时间
struct timespec64 i_mtime; // 最后修改文件时间
struct timespec64 i_ctime; // 最后修改 inode 时间
spinlock_t i_lock;
unsigned short i_bytes; // 文件中最后一个块的字节数
u8 i_blkbits; // 块大小
blkcnt_t i_blocks; // 文件占用块数,文件系统的特征。
unsigned long i_state;
struct hlist_node i_hash;
// 连接 hash 值相等的 inode,根据 inode 号+ 超级块地址定位到 hash 表找到 inode。
struct list_head i_io_list;
struct list_head i_lru;
struct list_head i_sb_list;
struct list_head i_wb_list;
union {
struct hlist_head i_dentry;
//连接了该 inode 所有 dentry,一个 inode 可有多个dentry,如硬链接。
struct rcu_head i_rcu;
};
atomic_t i_count; // 使用 inode 的引用计数
struct file_operations *i_fop;
struct address_space i_data;
union { // 文件类型
struct pipe_inode_info *i_pipe;
struct block_device *i_bdev;
struct cdev *i_cdev;
char *i_link;
unsigned i_dir_seq;
};
void *i_private;
};
struct inode 中复合数据类型的成员有:
1. inode操作
即 struct inode_operations *i_op;
struct inode_operations *i_op; 操作文件的属性。
struct file_operations *i_fop; 操作文件的数据。
struct inode_operations {
struct dentry *(*lookup) (struct inode *, struct dentry *, unsigned int);
//根据文件名查找其inode。
char *(*get_link) (struct dentry *, struct inode *, struct delayed_call *);
int (*readlink) (struct dentry *, char __user *, int);
int (*link) (struct dentry *, struct inode *, struct dentry *);
int (*symlink) (struct inode *, struct dentry *, const char *);
int (*unlink) (struct inode *, struct dentry *);
int (*mknod) (struct inode *, struct dentry *, umode_t,dev_t);
int (*create) (struct inode *, struct dentry *, umode_t, bool);
int (*rmdir) (struct inode *, struct dentry *);
int (*mkdir) (struct inode *, struct dentry *, umode_t);
int (*rename) (struct inode *, struct dentry *, struct inode *, struct dentry *, unsigned int);
int (*setattr) (struct dentry *, struct iattr *);
//扩展属性,实现文件ACL。
ssize_t (*listxattr) (struct dentry *, char *, size_t);
};
struct dentry 作用:
关联文件名及其 inode。
文件ACL:
提供比传统文件权限(user, group, others 的 rwx 权限)更细致管理。
可对指定用户或用户组设定指定权限。
相关系统调用:
setxattr()、getxattr()、listxattr()
命令工具:
setfacl、getfacl
setfacl 使用举例:
1. 赋予用户 john 读写权限:
setfacl -m u:john:rw file.txt
2. 删除用户 jane 的所有权限:
setfacl -x u:jane file.txt
注:某些文件系统不支持ACL。
2. inode链表
一个 inode 可被包含在:
1. 三个链表:
1.1. inode_unused 链表:
该inode未关联到任何文件。
1.2. inode_in_use 链表:
该inode关联到一个文件。
1.3. 一个超级块的脏 inode 链表。
2. 一个散列表:以支持根据 inode 编号和超级块访问 inode。
全局数组变量:inode_hashtable
struct inode {
struct hlist_node i_hash; // 用于连接 hash 冲突的 inode。
}
struct super_block { // 表示文件系统的信息。
struct list_head s_inodes; // 连接该文件系统所有 inode。
struct list_head s_dentry_lru; // 管理 dentry 缓存的 LRU 列表。
struct list_head s_inode_lru; // 管理 inode 缓存的 LRU 列表。
}
使用举例:
list_add(&dentry->d_lru, &dentry->d_sb->s_dentry_lru);
dentry = list_entry(sb->s_dentry_lru.prev, struct dentry, d_lru);
list_add(&inode->i_lru, &inode->i_sb->s_inode_lru);
inode = list_entry(sb->s_inode_lru.prev, struct inode, i_lru);