曾经在网上搜索过一个问题,为什么叫VFS--虚拟文件系统。网上有个帖子,给出了个这样的答案。虚拟文件系统,关键在于“虚拟”,也就是说VFS不是一个真正的文件系统,它仅仅提供真实文件系统的管理。另外有个帖子问一句话说什么是VFS,我觉得不错的回答是,VFS是文件系统与用户空间程序的一个接口。
1.与VFS相关的数据结构
超级块结构:存放已安装的系统文件的相关信息。
索引节点结构:存放有关文件的信息。
文件结构:存放被进程打开的文件的相关信息。
目录项:存放有关路径及路径名所指向的文件的信息。
1.1超级块结构
1.1.1
struct super_block
{
/************描述具体文件系统的整体信息的域*****************
kdev_t s_dev; /* 包含该具体文件系统的块设备标识符。
例如,对于 /dev/hda1,其设备标识符为 0x301*/
unsigned long s_blocksize; /*该具体文件系统中数据块的大小,以字节为位 */ unsigned char s_blocksize_bits; /*块大小的值占用的位数,例如,如果块大小为1024字节,则该值为10*/
unsigned long long s_maxbytes; /* 文件的最大长度 */
unsigned long s_flags; /* 安装标志*/
unsigned long s_magic; /*魔数,即该具体文件系统区别于其它文系统的一个标志*/
/**************用于管理超级块的域******************/
struct list_head s_list; /*指向超级块链表的指针*/
struct semaphore s_lock /*锁标志位,若置该位,则其它进程不能对该超级块操作*/
struct rw_semaphore s_umount /*对超级块读写时进行同步*/ unsigned char s_dirt; /*脏位,若置该位,表明该超级块已被修改*/
struct dentry *s_root; /*指向该具体文件系统安装目录的目录项。*/
int s_count; /*对超级块的使用计数*/
atomic_t s_active;
struct list_head s_dirty; /*已修改的索引节点形成的链表 */
struct list_head s_locked_inodes; /* 要进行同步的索引节点形成的链表*/
struct list_head s_files;
/***********和具体文件系统相联系的域*************************/
struct file_system_type *s_type; /*指向文件系统的file_system_type 数据结构的指针 */
struct super_operations *s_op; /*指向某个特定的具体文件系统的用于超级块操作的函数集合 */ struct dquot_operations *dq_op; /* 指向某个特定的具体文件系统用于限额操作的函数集合 */ struct quotact_ops *sqcop /*一个共用体,其成员是各种文件系统 的 fsname_sb_info数据结构 */ };
超级块的重要信息:
(1)s_list域
s_list域是list_head类型的,它指向双向循环链表中的前一个元素和下一个元素的指针,这个超级块被嵌入双向循环链表中。
(2)s_maxbytes
文件系统所允许的文件的最大长度。
(3)file_sysytm_type* s_type
超级块结构中包含通用文件系统的具体信息。
struct file_system_type {
const char *name; //文件系统的名称
int fs_flags;
int (*get_sb) (struct file_system_type *, int,const char *, void *, struct vfsmount *);
//这个函数用于取得本文件系统的super_block,并将之填充到相应的struct vfsmount的mnt_sb成员中。
void (*kill_sb) (struct super_block *);
struct module *owner;
struct file_system_type * next;
struct list_head fs_supers;
struct lock_class_key s_lock_key;
struct lock_class_key s_umount_key;
};
下图展示了文件系统和超级块之间的联系。
(4)super_operations *s_op
这个数据类型保存超级块的操作。
(5)s_dirty域
它指向属于这个文件系统的脏索引节点链表的第一个和最后一个元素。
(6)dentry *s_root
dentry结构体用于保存文件的路径名。这个特殊的dentry对象是与安装目录对应的目录项对象。这就是属于它的super_block。
(7)s_files
它指向文件结构体链表的第一个元素,这个文件结构体链表不但正在使用,而且已被分配给超级块。
(8)s_instances
它指向超级块链表中相邻的超级块元素,链表中的超级块是同一种文件系统。
1.1.2超级块的操作
它的定义在 include/linux/fs.h头文件中可以看到
1560struct super_operations {
1561 struct inode *(*alloc_inode)(struct super_block *sb);
1562 void (*destroy_inode)(struct inode *);
1563
1564 void (*dirty_inode) (struct inode *);
1565 int (*write_inode) (struct inode *, struct writeback_control *wbc);
1566 int (*drop_inode) (struct inode *);
1567 void (*evict_inode) (struct inode *);
1568 void (*put_super) (struct super_block *);
1569 void (*write_super) (struct super_block *);
1570 int (*sync_fs)(struct super_block *sb, int wait);
1571 int (*freeze_fs) (struct super_block *);
1572 int (*unfreeze_fs) (struct super_block *);
1573 int (*statfs) (struct dentry *, struct kstatfs *);
1574 int (*remount_fs) (struct super_block *, int *, char *);
1575 void (*umount_begin) (struct super_block *);
1576
1577 int (*show_options)(struct seq_file *, struct vfsmount *);
1578 int (*show_stats)(struct seq_file *, struct vfsmount *);
1579#ifdef CONFIG_QUOTA
1580 ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
1581 ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
1582#endif
1583 int (*bdev_try_to_free_page)(struct super_block*, struct page*, gfp_t);
1584};
a.struct inode * alloc_inode(struct super_block * sb) :创建和初始化一个新的索引结点。
b.void destroy_inode(struct super_block *sb) :释放指定的索引结点 。
c.void dirty_inode(struct inode *inode) :VFS在索引节点被修改时会调用此函数。
d.void write_inode(struct inode *inode, struct writeback_control *wbc) 将指定的inode写回磁盘。
e.void drop_inode( struct inode * inode):删除索引节点。
f.void put_super(struct super_block *sb) :用来释放超级块。
g.void write_super(struct super_block *sb):更新磁盘上的超级块。
h.void sync_fs(struct super_block *sb,in wait):使文件系统的数据元素与磁盘上的文件系统同步,wait参数指定操作是否同步。
i.int statfs(struct super_block *sb,struct statfs *statfs):获取文件系统状态。把文件系统相关的统计信息放在statfs中。
1.2索引节点的结构
文件系统处理文件或目录时的所有信息都存放在称为索引节点的数据结构中。具体文件系统的索引节点是存放在磁盘上的,是一种静态结构,要使用它,必须将其调入内存,填写VFS的索引节点。VFS索引节点也称为动态节点。(即索引节点仅当文件被访问的时候才在内存中创建)。
725struct inode {
726 struct hlist_node i_hash; //散列表
727 struct list_head i_list; //索引节点链表
728 struct list_head i_sb_list; //链接一个文件系统中所有inode的链表
729 struct list_head i_dentry; //目录项链表
730 unsigned long i_ino; //索引节点号
731 atomic_t i_count; //引用计数
732 unsigned int i_nlink; //硬连接数
733 uid_t i_uid; //使用者的id
734 gid_t i_gid; //使用组id
735 dev_t i_rdev; //实际设备标识符号
736 unsigned int i_blkbits;
737 u64 i_version; //版本号
738 loff_t i_size; //以字节为单位
739#ifdef __NEED_I_SIZE_ORDERED
740 seqcount_t i_size_seqcount;
741#endif
742 struct timespec i_atime; //最后访问时间
743 struct timespec i_mtime; //最后修改时间
744 struct timespec i_ctime; //最后改变时间
745 blkcnt_t i_blocks; //文件的块数
746 unsigned short i_bytes; //使用的字节数
747 umode_t i_mode; //访问权限控制
748 spinlock_t i_lock; //自旋锁
749 struct mutex i_mutex;
750 struct rw_semaphore i_alloc_sem;
751 const struct inode_operations *i_op; //索引节点操作表
752 const struct file_operations *i_fop; //文件操作表
753 struct super_block *i_sb; //相关的超级块
754 struct file_lock *i_flock; //文件锁链表
755 struct address_space *i_mapping; //相关的地址映射
756 struct address_space i_data; //设备地址映射
757#ifdef CONFIG_QUOTA
758 struct dquot *i_dquot[MAXQUOTAS]; //节点的磁盘限额
759#endif
760 struct list_head i_devices; //块设备链表
761 union {
762 struct pipe_inode_info *i_pipe; //管道信息
763 struct block_device *i_bdev; //块设备驱动
764 struct cdev *i_cdev;
765 };
766
767 __u32 i_generation; //索引节点版本号
768
769#ifdef CONFIG_FSNOTIFY
770 __u32 i_fsnotify_mask; /* all events this inode cares about */
771 struct hlist_head i_fsnotify_marks;
772#endif
773
774 unsigned long i_state; //状态标志
775 unsigned long dirtied_when; //首次修改时间
776
777 unsigned int i_flags; //文件系统标志
778
779 atomic_t i_writecount; //写者计数
780#ifdef CONFIG_SECURITY
781 void *i_security; //安全模块
782#endif
783#ifdef CONFIG_FS_POSIX_ACL
784 struct posix_acl *i_acl;
785 struct posix_acl *i_default_acl;
786#endif
787 void *i_private; /* fs or device private pointer */
788};
索引节点链表分成三类:
链表 | i_count | 是否脏 | 引用指针 |
未使用 | i_count=0 | 不脏 | inode_unused |
使用 | i_coun>0 | 不脏 | inode_in_use |
脏索引节点 | i_count>0 | 脏 | 超级块的s_dirty域 |
(1)i_hash域
它包含一个指向哈希表的指针,哈希表用来加速索引节点的查找。
(2)i_list域
这个域连接索引节点链表中相邻的结构。
(3)i_dentry
这个域指向与文件对应的dentry结构体的链表。
(4)i_ino域
这个域保存独一无二的索引节点号。
(5)i_sb域
这个域保存有一个指针指向文件所驻留的文件系统的超级块。
(6)i_state
带有I_LOCK 和I_DIRTY标志集的索引节点在inode_in_use链表。如果没有这两个标志,就把索引节点添加到inode_unuse链表。
1.3目录项结构
dentry结构表示目录中的一项。VFS用它了解基于系统目录命名、目录组织和文件逻辑布局之间的关系。
(1)d_inode域
d_inode指向与目录项相关的文件对应的索引节点。
(2)指向目录项链表中相邻元素的指针。
d_alias 指针指向已使用的目录项链表,d_lru指向未使用的目录项指针。
(3)dop域
d_op指向目录项的操作表
(4)d_sb域
指向与目录项表示的分量相关的超级块。
(5)d_parent
保存指向父目录项或路径名中父分量对应的目录项的指针。
1.4文件结构
89struct dentry {
90 atomic_t d_count; //使用计数
91 unsigned int d_flags; //目录项标时
92 spinlock_t d_lock; //单目录锁
93 int d_mounted; //目录项的安装点
94 struct inode *d_inode; //与该目录项相关联的索引节点
95
96 /*
97 * The next three fields are touched by __d_lookup. Place them here
98 * so they all fit in a cache line.
99 */
100 struct hlist_node d_hash; //散列表
101 struct dentry *d_parent; //父目录项
102 struct qstr d_name; //目录项名可快速查找
103
104 struct list_head d_lru; // 未使用目录以LRU 算法链接的链表
105 /*
106 * d_child and d_rcu can share memory
107 */
108 union {
109 struct list_head d_child; /* child of parent list */
110 struct rcu_head d_rcu;
111 } d_u;
112 struct list_head d_subdirs; //该目录项子目录项所形成的链表
113 struct list_head d_alias; //索引节点别名链表
114 unsigned long d_time; //重新生效时间
115 const struct dentry_operations *d_op; // 操作目录项的函数
116 struct super_block *d_sb; //目录项树的根
117 void *d_fsdata; //具体文件系统的数据
118
119 unsigned char d_iname[DNAME_INLINE_LEN_MIN]; //短文件名
120};
内核使用双向循环链表来保存文件结构。共有三个链表:
free_list全局变量,空闲文件对象链表,由所有可用的文件对象组成的双向链表。
anon_list全局变量,正在使用,但是没有分配的文件对象链表。
超级块的s_files,超级块的文件对象链表。
(1)f_list域
struct vfsmount { struct list_head mnt_hash; struct vfsmount *mnt_parent; /* fs we are mounted on */ struct dentry *mnt_mountpoint; /* dentry of mountpoint */ struct dentry *mnt_root; /* root of the mounted tree */ struct super_block *mnt_sb; /* pointer to superblock */ struct list_head mnt_mounts; /* list of children, anchored here */ struct list_head mnt_child; /* and going through their mnt_child */ int mnt_flags; /* 4 bytes hole on 64bits arches */ const char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */ struct list_head mnt_list; struct list_head mnt_expire; /* link in fs-specific expiry list */ struct list_head mnt_share; /* circular list of shared mounts */ struct list_head mnt_slave_list;/* list of slave mounts */ struct list_head mnt_slave; /* slave list entry */ struct vfsmount *mnt_master; /* slave is on master->mnt_slave_list */ struct mnt_namespace *mnt_ns; /* containing namespace */ atomic_t __mnt_writers; ... };
指向链表中相邻文件结构的指针。
(2)f_dentry域
指向与文件相关的目录项结构的指针。
(3)f_vfsmnt域
指向vfsmount结构的指针。
(4)f_op域
指向file_operations结构的指针,它被保存可被用应用于文件的操作表。
全局链表和局部链表的应用。
内核保存的全局变量以及这些变量指向的链表类型如下:
super_blocks super_block全局变量 结构类型
file_systems file_sysytem_type
dentry_unused dentry
vfsmountlist vfsmount
inode_in_use inode
inode_unuse inode