1,基本数据结构:
file_system_type
每种文件系统对应一个文件系统类型结构,注册之后形成单链表,链表表头为file_systems(全局变量).
Superblock
反应文件系统整体的控制信息,超级块以多种方式存在。(磁盘超级快、内存超级块、VFS超级块)
Inode
反应了某个文件系统对象的一般元信息(metadata)。(磁盘inode、内存inode、VFS inode)
Dentry
反应了某个文件系统对象在文件系统树中的位置。
mount
反映了一个已装载文件系统实例。
2,文件系统的注册
在register_filesystem()函数中来向内核注册文件系统,所有的文件系统都在一个单链表中,各个文件系统的名称存储为字符串,用于描述文件系统结构为file_system_type,内核中用一个名为file_systems 的全局变量来指向该链表的表头。
- struct file_system_type {
- const char *name; //保存了文件系统的名称,是一个字符串
- int fs_flags;
- struct super_block *(*get_sb) (struct file_system_type *, int,)//读超级块的方法,在文件系统装载时调用;在kern_mount函数中调用,用于取
- 得本文件系统(分区)的super_block,并将之填充到struct vfsmount的mnt_sb成员中。
- const char *, void *, struct vfsmount *);
- void (*kill_sb) (struct super_block *);//删除超级块的方法
- struct module *owner;
- struct file_system_type * next;
- struct list_head fs_supers;//相同类型文件系统的超级块对象双向链表头;每个文件系统都有一个超级块,但有些文件系统可能被安装在不同的设备上,而每个具体的设备都有一个超级块,这些形成一个链表
- };
在一个系统上,比如smartphone平台,有很多分区,比如/data和/system分区都是ext4文件系统,但是系统中还是只有一个file_system_type的成员,不过每个分区对应的ext4文件系统对应不同的super_block,fs_supers就是将这些相同文件系统不同的super block链接起来形成双向循环链表,fs_supers是链表头,链表元素由super_block结构体的s_instance成员表示。系统中所有的super_block由super_block结构体的s_list链接成双向循环链表,表头是super_blocks变量表示。
3,文件系统的装载和卸载
使用mount命令可以查询目录树中各种文件系统的装载情况, 在将文件系统装载到一个目录时,装载点的内容被替换为即将装载的文件系统的相对根目录的内容,前一个目录数据消失,直到新文件系统卸载的时候才重新出现。
- 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;
- 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_count;
- int mnt_expiry_mark; /* true if marked for expiry */
- };
vfsmount成员mnt_mountpoint表示的是装载点在父文件系统中的dentry,文件系统本身的相对根目录所对应的dentry保存在mnt_root中,两个dentry实例表示同一目录,这意味着在文件系统卸载后不必删除此前的装载点信息。
在新版本的linux内核中,使用了struct mount结构体代替了struct vfsmount结构体。
在装载新的文件系统时,vfsmount并不是唯一需要在内存中创建的结构,装载操作开始于超级块的读取,超级块是整个文件系统的元数据的容器。基于磁盘的文件系统,超级块(磁盘上的)是保存在磁盘设备上固定位置的一个或多个块,在装载该磁盘上的文件系统时,磁盘上的超级块被读入内存,并根据它构造内存中的超级块。
- struct super_block {
- struct list_head s_list; /* 链表元素,表头super_blokcs,标示所有的超级块链表,指向链表相邻元素指针,
- dev_t s_dev; /* 存储超级块信息的块设备
- unsigned long s_blocksize;
- unsigned char s_blocksize_bits; //文件系统的块长度,以位的形式标示
- unsigned char s_dirt; //超级块是否写脏,需要回写到磁盘
- unsigned long long s_maxbytes; /* 支持的文件的最大长度,默认是231-1
- struct file_system_type *s_type; //指向file_system_type类型的指针
- struct super_operations *s_op;
- unsigned long s_flags; //s_flags 这个标志为设置为1或者0,用以表示整个设备上的文件是否允许使用强制锁。
- unsigned long s_magic;
- struct dentry *s_root; //指向文件系统根目录的dentry对象
- struct xattr_handler **s_xattr;
- struct list_head s_inodes; /* 文件系统的所有inode链表的表头
- struct list_head s_dirty; /* 指向所有dirty的inode对象 */
- struct list_head s_io; /* parked for writeback */
- struct list_head s_more_io; /* parked for more writeback */
- struct list_head s_files; //表头,所有打开的文件
- struct block_device *s_bdev; //对于磁盘文件系统,指向块设备描述符的指针,否则为空
- struct list_head s_instances; //链表元素,表头file_system_type->fs_supers,标示同一个文件系统的多次装载链表
- char s_id[32]; /* 具体设备名,比如为/dev/block/mmcblkop1 */
- void *s_fs_info; /* 指向具体文件系统的super block结构,比如fat32对应的结构体是msdos_sb_info结构体*/
- u32 s_time_gran;
- };
超级快可以管理系统中inode节点的原因是文件系统内所有的inode要链接到超级快的链表头。
所有超级快对象都以双向循环链表的形式连接在一起,链表第一个元素用super_blocks变量表示,sb_lock自旋锁保护链表免受多处理器系统上的同时访问。s_fs_info指向属于具体文件系统的超级快信息,例如具体文件系统是EXT2,则s_fs_info指向ext2_sb_info,s_dirty表示的修改脏标记,表示内存中的超级快信息是否和硬盘上超级快信息同步,
对于每个转载的文件系统而言,都有且只有一个超级快实例
- 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; //缺省文件操作
- struct super_block *i_sb; //指向超级快对象的指针
- struct address_space *i_mapping; //指向address_space对象的指针
- struct address_space i_data; //文件的address_space对象
- 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 of first dirtying */
- unsigned int i_flags; //文件系统安装标志,比如为MS_MANDLOCK可以有选择的对一个文件是否使用强制锁。
- atomic_t i_writecount; //用于写进程的引用计数
- void *i_security; //指向索引节点安全结构指针
- };