VFS
概念
虚拟文件系统(也称为虚拟文件系统交换机)是内核中的软件层,为用户空间程序提供文件系统接口。它还在内核中提供了一个抽象,允许不同的文件系统实现共存
"一切皆文件"是Linux的基本哲学之一,不仅是普通的文件,包括目录、字符设备、块设备、套接字等,都可以以文件的方式被对待。实现这一行为的基础,正是Linux的虚拟文件系统机制。。
还记得系统调用吧?你可以VFS类似给各种文件系统抽象出来了一个系统调用,把各种类型的文件系统封装成对上层不可见的,同时留出一些api。示意图如下
VFS设计
Linux为了实现这种VFS系统,采用面向对象的设计思路,主要抽象了四种对象类型:
- 超级块对象:代表一个已安装的文件系统。 (struct super_block)
- 索引节点对象:代表具体的文件。 (struct inode)
- 目录项对象:代表一个目录项,是文件路径的一个组成部分。 (struct denrtry)
- 文件对象:代表进程打开的文件。 (struct file)
容易混淆的地方
Linux将目录当做文件对象来处理,是另一种形式的文件,它里面包含了一个或多个目录项。而目录项是单独抽象的对象,主要包括文件名和索引节点号。因为目录是可以层层嵌套,以形成文件路径,而路径中的每一部分,其实就是目录项。
struct super_block (代表一个已安装的文件系统)
include/linux/fs.h
超级块代表的是一种文件系统类型,比如ext3、ext4都有对应的super_block结构体。一台机器可以有多块硬盘,一个硬盘可以有多个分区,每个分区都有自己的文件系统类型,超级块同时也维护跟这个文件系统有关的各种信息。 各个super_block由链表组织
struct super_block {
struct list_head s_list;
dev_t s_dev;
unsigned char s_blocksize_bits;
unsigned long s_blocksize;
loff_t s_maxbytes;
struct file_system_type *s_type;
const struct super_operations *s_op;
const struct dquot_operations *dq_op;
const struct quotactl_ops *s_qcop;
const struct export_operations *s_export_op;
unsigned long s_flags;
unsigned long s_iflags;
unsigned long s_magic;
struct dentry *s_root;
...
struct block_device *s_bdev;
struct backing_dev_info *s_bdi;
struct mtd_info *s_mtd;
struct hlist_node s_instances;
...
char s_id[32];
uuid_t s_uuid;
void *s_fs_info;
...
const struct dentry_operations *s_d_op;
...
struct shrinker s_shrink;
...
struct workqueue_struct *s_dio_done_wq;
...
struct list_lru s_dentry_lru ____cacheline_aligned_in_smp;
struct list_lru s_inode_lru ____cacheline_aligned_in_smp;
...
spinlock_t s_inode_list_lock ____cacheline_aligned_in_smp;
struct list_head s_inodes;
spinlock_t s_inode_wblist_lock;
struct list_head s_inodes_wb;
};
ps:超级块的信息是可读的!通过cat 某个文件可以human readab。具体是哪个我忘了。。。在油管一个视频上看到的
const struct dentry_operations *s_d_op 存放着文件系统的目录项操作函数(函数指针)
struct file_system_type
超级块是实装的文件系统,file_system_type专注于描述这个这个文件系统的类型,由链表组织
每种文件系统都要把自己的信息挂到super_blocks这么一个全局链表上
file_system_type挂载到super_block
内核中是分成2个步骤完成:
首先每个文件系统必须通过register_filesystem函数将自己的file_system_type挂接到file_systems这个全局变量上,
然后调用kern_mount函数把自己的文件相关操作函数集合表挂到super_blocks上。每种文件系统类型的读超级块的例程(get_sb)必须由自己实现。
struct file_system_type {
const char *name;
...
struct dentry *(*mount) (struct file_system_type *, int,
const char *, void *);
void (*kill_sb) (struct super_block *);
struct module *owner;
struct file_system_type * next;
struct hlist_head fs_supers;
...
};
struct inode (物理Device storage的具体对象)
当创建一个文件的时候,就给文件分配了一个inode。一个inode只对应一个实际文件,一个文件也会只有一个inode。inodes最大数量就是文件的最大数量。
inode结构中的静态信息取自物理设备上的文件系统,由文件系统指定的函数填写,它只存在于内存中,可以通过inode缓存访问。
struct inode {
struct list_headi_hash;
struct list_headi_list;
struct list_headi_dentry;
struct list_headi_dirty_buffers;
unsigned longi_ino;
atomic_t i_count;
kdev_t i_dev;
umode_t i_mode;
nlink_t i_nlink;
uid_t i_uid;
gid_t i_gid;
kdev_t i_rdev;
off_t i_size;
time_t i_atime;
time_t i_mtime;
time_t i_ctime;
unsigned long i_blksize;
unsigned long i_blocks;
unsigned long i_version;
unsigned short i_bytes;
struct semaphore i_sem;
struct rw_semaphore i_truncate_sem;
struct semaphore i_zombie;
struct inode_operations *i_op;
struct file_operations *i_fop;
struct super_block *i_sb;
wait_queue_head_t i_wait;
struct file_lock *i_flock;
struct address_space *i_mapping;
struct address_space i_data;
struct dquot *i_dquot [MAXQUOTAS];
struct pipe_inode_info *i_pipe;
struct block_device *i_bdev;
struct char_device *i_cdev;
unsigned longi_dnotify_mask;
struct dnotify_struct *i_dnotify;
unsigned long i_state;
unsigned int i_flags;
unsigned char i_sock;
atomic_t i_write count;
unsigned int i_attr_flags;
__u32 i_generation;
union {
struct minix_inode_info minix_i;
struct ext2_inode_info ext2_i;
struct ext3_inode_info ext3_i;
struct hpfs_inode_info hpfs_i;
struct ntfs_inode_info ntfs_i;
struct msdos_inode_info msdos_i;
struct umsdos_inode_info umsdos_i;
struct iso_inode_info isofs_i;
struct sysv_inode_info sysv_i;
struct affs_inode_info affs_i;
struct ufs_inode_info ufs_i;
struct efs_inode_info efs_i;
struct romfs_inode_info romfs_i;
struct shmem_inode_info shmem_i;
struct coda_inode_info coda_i;
struct smb_inode_info smbfs_i;
struct hfs_inode_info hfs_i;
struct adfs_inode_info adfs_i;
struct qnx4_inode_info qnx4_i;
struct reiserfs_inode_info reiserfs_i;
struct bfs_inode_info bfs_i;
struct udf_inode_info udf_i;
struct ncp_inode_info ncpfs_i;
struct proc_inode_info proc_i;
struct socketsocket_i;
struct usbdev_inode_info usbdev_i;
struct jffs2_inode_infojffs2_i;
void *generic_ip;
} u;
};
虽然每个文件都有相应的inode结点,但是只有在需要的时候系统才会在内存中为其建立相应的inode数据结构,建立的inode结构将形成一个链表,我们可以通过遍历这个链表去得到我们需要的文件结点,
struct dentry (主存中的一个实体)
为什么引入dentry
引入目录项结构是很有必要的,因为同一个文件有且仅有一个inode对象表示,而由于硬链接的存在,对同一文件的访问可以通过不同的文件名,所以中间需要引入目录项
struct dentry {
atomic_t d_count;
unsigned int d_flags;
spinlock_t d_lock;
struct inode *d_inode;
struct hlist_node d_hash;
struct dentry *d_parent;
struct qstr d_name;
struct list_head d_lru;
union {
struct list_head d_child;
struct rcu_head d_rcu;
} d_u;
struct list_head d_subdirs;
struct list_head d_alias;
unsigned long d_time;
struct dentry_operations *d_op;
struct super_block *d_sb;
void *d_fsdata;
struct dcookie_struct *d_cookie;
int d_mounted;
unsigned char d_iname[DNAME_INLINE_LEN_MIN];
};
目录项的三种状态
1.正在使用 d_count > 0
2.未被使用 d_count == 0
3.负状态 d_inode == NULL 目录项对象没有对应的有效索引节点
struct file (被打开的文件对象)
include/Linux/fs.h
文件结构体代表一个打开的文件,系统中的每个打开的文件在内核空间都有一个关联的 struct file。它由内核在打开文件时创建,并传递给在文件上进行操作的任何函数。在文件的所有实例都关闭后,内核释放这个数据结构。在内核创建和驱动源码中,struct file的指针通常被命名为file或filp
struct file {
union {
struct list_head fu_list;
struct rcu_head fu_rcuhead;
} f_u;
struct path f_path;
#define f_dentry f_path.dentry
#define f_vfsmnt f_path.mnt
const struct file_operations *f_op;
atomic_t f_count;
unsigned int f_flags;
mode_t f_mode;
loff_t f_pos;
off_t f_pos;
struct fown_struct f_owner;
unsigned int f_uid, f_gid;
struct file_ra_state f_ra;
unsigned long f_version;
#ifdef CONFIG_SECURITY
void *f_security;
#endif
void *private_data;
#ifdef CONFIG_EPOLL
struct list_head f_ep_links;
spinlock_t f_ep_lock;
#endif
struct address_space *f_mapping;
};
dentry与inode
inode(可理解为ext2 inode)对应于物理磁盘上的具体对象,dentry是一个内存实体,其中的d_inode成员指向对应的inode。也就是说,一个inode可以在运行的时候链接多个dentry,而d_count记录了这个链接的数量。
按照d_count的值,dentry分为以下三种状态:
1.正在使用 d_count > 0
2.未被使用 d_count == 0
3.负状态 d_inode == NULL 目录项对象没有对应的有效索引节点
File_system_type -->file_system —>super_block关系图
VFS中各个重要数据结构关系图
|