参考原文
http://blog.163.com/xujian900308@126/blog/static/126907615201191985817385/
http://blog.163.com/xujian900308@126/blog/static/12690761520119198237958/
VFS的实现,其主要思想是引入了一个通用的文件模型(common file model),这个模型的核心是四个对象类型,即超级块对象(superblock object)、索引节点对象(inode object)、文件对象(file object)和目录项对象(dentry object),它们都是内核空间中的数据结构,是VFS的核心
1. super block 存储文件系统相关的信息,对于磁盘文件系统来说,这个对象通常对应磁盘上的一个文件系统控制块(磁盘super block)
2. inode 存储一个文件相关的信息,对于磁盘文件系统,这个对象通常对应磁盘上的一个文件控制块(磁盘inode)。每一个inode都对应一个编号,可以在文件系统内唯一标识这个文件。
3. file file是和进程相关的,file代表一个打开的文件,file和inode之间是多对一的关系,因为多个进程可以打开同一个文件,系统会为每一次打开都创建一个file结构。存放已代开文件和进程之间的交互信息
4. dentry 存放目录项与文件之间的链接信息 底层文件系统的许多操作严重依赖文件的inode,在进行文件操作前,我们需要根据路径名找到文件对应的inode。我们知道文件系统是树状结构的,因此需要从根目录通过目录树找到要操作的文件或目录,这个遍历过程涉及到磁盘操作,非常耗时。根据局部性原理,很有必要把这个查找过程cache起来,dentry就是为了加快目录遍历操作引入的数据结构。
///////////////////////////////////////////////
/////////////////////////////////////////////////
////////////////////////////////////////////////////////
内核使用三种数据结构表示打开的文件:
(1)每个进程在进程表中都有一个记录项,记录项包含一张打开的文件描述符表,可将视为矢量,每个描述符占用一项,与每个文件描述符相关联的是:
a)文件描述符标志(close_on_exec).
b))指向一个文件表项的指针。
(2)内核为所用打开文件维持一张文件表,每个文件表项包含:
a)文件状态标志(读写等等)
b)当前文件偏移量。
c)指向该文件V节点表项的指针。
(3)每个打开文件(或设备)都有一个V-node结构。v节点包含了文件类型和对此文件进行各种操作的函数指针。对于大多数文件V节点还包含文件的i节点(索引节点)。这些信息时在打开文件时从磁盘上读入内存的。对于linux没有V节点
1、file结构体
文件结构体代表一个打开的文件(设备对应于设备文件),系统在每次打开一个文件的时候都会创建一个file结构体表示此时打开的文件,又内核在打开时创建,当文件的所有实例被关闭的时候(关闭该文件同时引用该文件)该file结构体将被内核释放。
include/linux/fs.h
struct file {
/*
* fu_list becomes invalid after file_free is called and queued via
* fu_rcuhead for RCU freeing
*/
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 //作用是指出该文件的已安装的文件系统
// 被定义在include/linux/fs.h中,其中包含着与文件关联的操作
const struct file_operations *f_op;//该操作是定义文件关联的操作的,内核在执行open时对这个指针赋值。
atomic_long_t f_count;//此处f_count的作用是记录对文件对象的引用计数,也即当前有多少个进程在使用该文件。
unsigned int f_flags;
//该成员是文件标志。
// 当打开文件时指定的标志,对应系统调用open的int flags参数。驱动程序为了支持非阻塞型操作需要检查这个标志。
fmode_t f_mode; //对文件的读写模式,对应系统调用open的mod_t mode参数如果驱动程序需要这个值,可以直接读取这个字段
loff_t f_pos;//当前的文件指针位置,即文件的读写位置 ,文件偏移量
struct fown_struct f_owner;//通过信号进行I/O事件通知的数据??
unsigned int f_uid, f_gid;//标识文件的所有者id(UID),所有者所在组的id.(GID)
struct file_ra_state f_ra;//文件预读状态,文件预读算法使用的主要数据结构,
//当打开一个文件时,f_ra中出了perv_page(默认为-1)和ra_apges(对该文件允许的最大预读量)这两个字段外
//其他的所有西端都置为0。
u64 f_version; //记录文件的版本号,每次使用后都自动递增
#ifdef CONFIG_SECURITY
void *f_security; //指向文件对象的安全结构的指针
#endif
/* needed for tty driver, and maybe others */
//指向特定文件系统或设备驱动程序所需的数据的指针
void *private_data;//该成员是系统调用时保存状态信息非常有用的资源。
#ifdef CONFIG_EPOLL
/* Used by fs/eventpoll.c to link all the hooks to this file */
struct list_head f_ep_links; //文件的事件轮询等待者链表的头
spinlock_t f_ep_lock; //保护 f_ep_links链表的自旋锁
#endif /* #ifdef CONFIG_EPOLL */
struct address_space *f_mapping;//指向文件地址空间对象的指针
#ifdef CONFIG_DEBUG_WRITECOUNT
unsigned long f_mnt_write_state;
#endif
};
include/linux/path.h
struct path {
struct vfsmount *mnt; //作用是指出该文件的已安装的文件系统
struct dentry *dentry; //该成员是对应的 目录结构 。
};
include/linux/dcache.h
在内核中有一个哈希表dentry_hashtable ,是一个list_head的指针数组。一旦在内存中建立起一个目录节点的dentry 结构,该dentry结构就通过其d_hash域链入哈希表中的某个队列中。
内核中还有一个队列dentry_unused,凡是已经没有用户(count域为0)使用的dentry结构就通过其d_lru域挂入这个队列。
Dentry结构中除了d_alias 、d_hash、d_lru三个队列外,还有d_vfsmnt、d_child及d_subdir三个队列。其中d_vfsmnt仅在该dentry为一个安装点时才使用。另外,当该目录节点有父目录时,则其dentry结构就通过d_child挂入其父节点的d_subdirs队列中,同时又通过指针d_parent指向其父目录的dentry结构,而它自己各个子目录的dentry结构则挂在其d_subdirs域指向的队列中。
从上面的叙述可以看出,一个文件系统中所有目录项结构或组织为一个哈希表,或组织为一颗树,或按照某种需要组织为一个链表,这将为文件访问和文件路径搜索奠定下良好的基础
struct dentry {
atomic_t d_count;
unsigned int d_flags; /* protected by d_lock */
spinlock_t d_lock; /* per dentry lock */
struct inode *d_inode; /* Where the name belongs to - NULL is
* negative */
/*
* The next three fields are touched by __d_lookup. Place them here
* so they all fit in a cache line.
*/
struct hlist_node d_hash; /* lookup hash list */
struct dentry *d_parent; /* parent directory */
struct qstr d_name;
struct list_head d_lru; /* LRU list */
/*
* d_child and d_rcu can share memory
*/
union {
struct list_head d_child; /* child of parent list */
struct rcu_head d_rcu;
} d_u;
struct list_head d_subdirs; /* our children */
struct list_head d_alias; /* inode alias list */
unsigned long d_time; /* used by d_revalidate */
struct dentry_operations *d_op;
struct super_block *d_sb; /* The root of the dentry tree */
void *d_fsdata; /* fs-specific data */
#ifdef CONFIG_PROFILING
struct dcookie_struct *d_cookie; /* cookie, if any */
#endif
int d_mounted;
unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */
};
用户调用系统调用read来读取该文件的内容时,那么系统调用read最终会陷入内核调用sys_read函数,而sys_read最终会调用于该文件关联的struct file结构中的f_op->read函数对文件内容进行读取。
include/linux/mount.h
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 */
int mnt_id; /* mount identifier */
int mnt_group_id; /* peer group identifier */
/*
* We put mnt_count & mnt_expiry_mark at the end of struct vfsmount
* to let these frequently modified fields in a separate cache line
* (so that reads of mnt_flags wont ping-pong on SMP machines)
*/
atomic_t mnt_count;
int mnt_expiry_mark; /* true if marked for expiry */
int mnt_pinned;
int mnt_ghosts;
/*
* This value is not stable unless all of the mnt_writers[] spinlocks
* are held, and all mnt_writer[]s on this mount have 0 as their ->count
*/
atomic_t __mnt_writers;
};
· 为了对系统中的所有安装点进行快速查找,内核把它们按哈希表来组织,mnt_hash就是形成哈希表的队列指针。
· mnt_mountpoint是指向安装点dentry结构的指针。而dentry指针指向安装点所在目录树中根目录的dentry结构。
·
mnt_parent是指向上一层安装点的指针。如果当前的安装点没有上一层安装点(如根设备),则这个指针为NULL。同时,vfsmount结构中还有mnt_mounts和mnt_child两个队列头,只要上一层vfsmount结构存在,就把当前vfsmount结构中mnt_child链入上一层vfsmount结构的mnt_mounts队列中。这样就形成一颗设备安装的树结构,从一个vfsmount结构的mnt_mounts队列开始,可以找到所有直接或间接安装在这个安装点上的其他设备。
· mnt_sb指向所安装设备的超级块结构super_blaock。
· mnt_list是指向vfsmount结构所形成链表的头指针。
另外,系统还定义了vfsmntlist变量,指向mnt_list队列。对这个数据结构的进一步理解请看后面文件系统安装的具体实现过程。
文件系统的安装选项,也就是vfsmount结构中的安装标志mnt_flags在linux/fs.h中定义如下:
/** These are the fs-independent mount-flags: up to 32flags are supported*/
#define MS_RDONLY 1
/*Mount read-only */
#define MS_NOSUID 2
/*Ignore suid and sgid bits */
#define MS_NODEV 4
/*Disallow access to device special files */
#define MS_NOEXEC 8
/*Disallow program execution */
#define MS_SYNCHRONOUS 16
/* Writes are synced at once */
#define MS_REMOUNT 32
/* Alter flags of a mounted FS */
#define MS_MANDLOCK 64
/* Allow mandatory locks on an FS */
#define MS_NOATIME 1024
/* Do not update access times. */
#define MS_NODIRATIME 2048
/* Do not update directory access times */
#define MS_BIND 4096
#define MS_MOVE 8192
#define MS_REC 16384
#define MS_VERBOSE 32768
#define MS_ACTIVE (1<<30)
#define MS_NOUSER (1<<31)
从定义可以看出,每个标志对应32位中的一位。安装标志是针对整个文件系统中的所有文件的。例如,如果MS_NOSUID标志为1,则整个文件系统中所有可执行文件的suid标志位都不起作用了
///////////////////////
/*
* NOTE:
* read, write, poll, fsync, readv, writev, unlocked_ioctl and compat_ioctl
* can be called without the big kernel lock held in all filesystems.
*/
include/linux/fs.h
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);//更新文件指针
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);// 启动一个异步I/O操作(读)
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
int (*readdir) (struct file *, void *, filldir_t);//返回一个目录的下一个目录项,返回值存入参数void *dirent
unsigned int (*poll) (struct file *, struct poll_table_struct *);//检查是否在一个文件上有操作发生,休眠直到有操作发生
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);//向一个基本硬件设备发送命令,只适应于设备文件
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);//与ioctl方法类似,但是不获取大内核锁
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);//64位的内核使用该方法执行32位的系统调用 ioctl()
int (*mmap) (struct file *, struct vm_area_struct *);//执行文件的内存映射,并将映射放入进程的地址空间
int (*open) (struct inode *, struct file *);//创建,打开文件,并把它链接到相应的索引节点对象
int (*flush) (struct file *, fl_owner_t id);//当文件的引用被关闭时调用该方法,用途取决于文件系统
int (*release) (struct inode *, struct file *);//是否文件对象,当打开的最后一个引用被关闭时(文件对象f_count值为0时)调用该方法
int (*fsync) (struct file *, struct dentry *, int datasync);将文件所缓存的全部数据写入磁盘
int (*aio_fsync) (struct kiocb *, int datasync);//启动一次异步IO刷新操作
int (*fasync) (int, struct file *, int);//通过信号来启动或禁止IO事件通告
int (*lock) (struct file *, int, struct file_lock *);//对file文件申请一个锁
//将数据从文件传送到页高速缓存的页;这个低层方法有sendfile()和用于套接字的网络代码使用
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
//获得一个未用的地址范围来映射文件
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);//当设置文件的状态(F_SETFL)时,fcntl()系统调用的服务例程调用该方法执行附加检查
int (*dir_notify)(struct file *filp, unsigned long arg);//当建立一个目录更改通告(F_NOTIFY)时,由fcntl()系统调用的服务例程调用该方法
int (*flock) (struct file *, int, struct file_lock *);//用于定制flock()系统调用的行为
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **);
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
*索引节点对象由inode结构体表示,定义文件在linux/fs.h中
*/
include/linux/fs.h
struct inode {
struct hlist_node i_hash; /* 哈希表 */
struct list_head i_list; /* 索引节点链表 */用于描述索引节点当前状态的链表的指针
struct list_head i_list; //用于超级快的索引节点链表的指针
struct list_head i_dentry; /* 目录项链表 */
unsigned long i_ino; /* 节点号 */索引节点号
atomic_t i_count; /* 引用记数 */
umode_t i_mode; /* 访问权限控制 */文件类型与访问权限
unsigned int i_nlink; /* 硬链接数 */
uid_t i_uid; /* 使用者id */所有者标识
gid_t i_gid; /* 使用者id组 */组标识符
kdev_t i_rdev; /* 实设备标识符 */
loff_t i_size; /* 以字节为单位的文件大小 */
struct timespec i_atime; /* 最后访问时间 */
struct timespec i_mtime; /* 最后修改(modify)时间 */
struct timespec i_ctime; /* 最后改变(change)时间 */
unsigned int i_blkbits; /* 以位为单位的块大小 */
unsigned long i_blksize; /* 以字节为单位的块大小 */
unsigned long i_version; /* 版本号 */
unsigned long i_blocks; /* 文件的块数 */
unsigned short i_bytes; /* 使用的字节数 */
spinlock_t i_lock; /* 保护索引节点一些字段的自旋锁 */
struct rw_semaphore i_alloc_sem; /* 索引节点信号量 */
struct inode_operations *i_op; /* 索引节点操作表 */
struct file_operations *i_fop; /* 默认的索引节点操作 */缺省的文件操作
struct super_block *i_sb; /* 相关的超级块 */指向超级快对象的指针
struct file_lock *i_flock; /* 文件锁链表 */指针
struct address_space *i_mapping; /* 相关的地址映射 */指向address_space对象的指针
struct address_space i_data; /* 设备地址映射 */文件的address_space对象
struct dquot *i_dquot[MAXQUOTAS]; /* 节点的磁盘限额 */
struct list_head i_devices; /* 块设备链表 */用于具体的字符或块设备索引节点链表的指针
struct pipe_inode_info *i_pipe; /* 管道信息 */
struct block_device *i_bdev; /* 块设备驱动 */指向块设备驱动程序的指针
struct cdev *i_cdev; //指向字符设备驱动程序的指针
int i_cindex; //拥有一组次设备号的设备文件的索引
__u32 i_generation; //索引节点版本号
unsigned long i_dnotify_mask; /* 目录通知掩码 */目录通知事件的为掩码
struct dnotify_struct *i_dnotify; /* 目录通知 */
#ifdef CONFIG_INOTIFY
struct list_head inotify_watches; /* watches on this inode */
struct mutex inotify_mutex; /* protects the watches list */
#endif
unsigned long i_state; /* 状态标志 */索引节点的状态标致
unsigned long dirtied_when; /* 首次修改时间 */索引节点的弄脏时间
unsigned int i_flags; /* 文件系统标志 */文件系统的安装标致
unsigned char i_sock; /* 可能是个套接字吧 */
atomic_t i_writecount; /* 写者记数 */用于写进程的引用计数器
void *i_security; /* 安全模块 */指向索引节点安全结构的指针
__u32 i_generation; /* 索引节点版本号 */
void *i_private; /* fs or device private pointer */
};
/*
*索引节点的操作inode_operations定义在linux/fs.h中 inode的方法
*/
struct inode_operations {
int (*create) (struct inode *, struct dentry *,int);
/*VFS通过系统调用create()和open()来调用该函数,从而为dentry对象创建一个新的索引节点。在创建时使用mode制定初始模式*/
struct dentry * (*lookup) (struct inode *, struct dentry *);
/*该韩式在特定目录中寻找索引节点,该索引节点要对应于dentry中给出的文件名*/
int (*link) (struct dentry *, struct inode *, struct dentry *);
/*该函数被系统调用link()电泳,用来创建硬连接。硬链接名称由dentry参数指定,连接对象是dir目录中ld_dentry目录想所代表的文件*/
int (*unlink) (struct inode *, struct dentry *);
/*该函数被系统调用unlink()调用,从目录dir中删除由目录项dentry制动的索引节点对象*/
int (*symlink) (struct inode *, struct dentry *, const char *);
/*该函数被系统电泳symlik()调用,创建符号连接,该符号连接名称由symname指定,连接对象是dir目录中的dentry目录项*/
int (*mkdir) (struct inode *, struct dentry *, int);
/*该函数被mkdir()调用,创建一个新鲁姆。创建时使用mode制定的初始模式*/
int (*rmdir) (struct inode *, struct dentry *);
/*该函数被系统调用rmdir()调用,删除dir目录中的dentry目录项代表的文件*/
int (*mknod) (struct inode *, struct dentry *, int, dev_t);
/*该函数被系统调用mknod()调用,创建特殊文件(设备文件、命名管道或套接字)。要创建的文件放在dir目录中,其目录项问dentry,关联的设备为rdev,初始权限由mode指定*/
int (*rename) (struct inode *, struct dentry *,
struct inode *, struct dentry *);
/*VFS调用该函数来移动文件。文件源路径在old_dir目录中,源文件由old_dentry目录项所指定,目标路径在new_dir目录中,目标文件由new_dentry指定*/
int (*readlink) (struct dentry *, char *, int);
/*该函数被系统调用readlink()调用,拷贝数据到特定的缓冲buffer中。拷贝的数据来自dentry指定的符号链接,最大拷贝大小可达到buflen字节*/
int (*follow_link) (struct dentry *, struct nameidata *);
/*该函数由VFS调用,从一个符号连接查找他指向的索引节点,由dentry指向的连接被解析*/
int (*put_link) (struct dentry *, struct nameidata *);
/*在follow_link()调用之后,该函数由vfs调用进行清楚工作*/
void (*truncate) (struct inode *);
/*该函数由VFS调用,修改文件的大小,在调用之前,索引节点的i_size项必须被设置成预期的大小*/
int (*permission) (struct inode *, int);
/*该函数用来检查给低昂的inode所代表的文件是否允许特定的访问模式,如果允许特定的访问模式,返回0,否则返回负值的错误码。多数文件系统都将此区域设置为null,使用VFS提供的通用方法进行检查,这种检查操作仅仅比较索引及诶但对象中的访问模式位是否和mask一致,比较复杂的系统,比如支持访问控制链(ACL)的文件系统,需要使用特殊的permission()方法*/
int (*setattr) (struct dentry *, struct iattr *);
/*该函数被notify_change调用,在修改索引节点之后,通知发生了改变事件*/
int (*getattr) (struct vfsmount *, struct dentry *, struct kstat *);
/*在通知索引节点需要从磁盘中更新时,VFS会调用该函数*/
int (*setxattr) (struct dentry *, const char *,
const void *, size_t, int);
/*该函数由VFS调用,向dentry指定的文件设置扩展属性,属性名为name,值为value*/
ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
/*该函数被VFS调用,向value中拷贝给定文件的扩展属性name对应的数值*/
ssize_t (*listxattr) (struct dentry *, char *, size_t);
/*该函数将特定文件所有属性别表拷贝到一个缓冲列表中*/
int (*removexattr) (struct dentry *, const char *);
/*该函数从给定文件中删除指定的属性*/
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
超级块在linux/fs.h中
struct super_block {
struct list_head s_list; /* Keep this first */ 指向超级快链表的指针
dev_t s_dev; /* search index; _not_ kdev_t */设备标识符
unsigned long s_blocksize; //以字节为单位的快的大小
unsigned char s_blocksize_bits; // 基本块设备驱动程序中提到的以字节为单位的块大小
unsigned char s_dirt; //修改(脏)标致
unsigned long long s_maxbytes; /* Max file size */ 文件的最大长度
struct file_system_type *s_type;//文件系统类型
const struct super_operations *s_op;//超级块方法 与超级快关联的操作
struct dquot_operations *dq_op; //磁盘限额处理方法
struct quotactl_ops *s_qcop; //磁盘限额管理方法
const struct export_operations *s_export_op; //网络文件系统使用的输出操作
unsigned long s_flags; //安装标志
unsigned long s_magic; //文件系统的魔数
struct dentry *s_root; //文件系统跟目录的目录项对象
struct rw_semaphore s_umount; //卸载所用的信号量
struct mutex s_lock; //超级块信号量
int s_count; //引用计数器
int s_need_sync_fs;//对超级快的已安装文件系统进行同步的标志
atomic_t s_active; //次级引用计数器
#ifdef CONFIG_SECURITY
void *s_security; //指向超级快安全数据结构的指针
#endif
struct xattr_handler **s_xattr; //指向超级快扩展属性结构的指针
struct list_head s_inodes; /* all inodes */ 所用索引节点的链表
struct list_head s_dirty; /* dirty inodes */ 改进型索引节点的链表
struct list_head s_io; /* parked for writeback */等待被写入磁盘的索引节点的链表
struct list_head s_more_io; /* parked for more writeback */
struct hlist_head s_anon; /* anonymous dentries for (nfs) exporting */用于处理远程网络文件系统的匿名目录项的链表
struct list_head s_files; //文件对象的链表
/* s_dentry_lru and s_nr_dentry_unused are protected by dcache_lock */
struct list_head s_dentry_lru; /* unused dentry lru */
int s_nr_dentry_unused; /* # of dentry on lru */
struct block_device *s_bdev;//指向块设备驱动程序描述符的指针
struct mtd_info *s_mtd;
struct list_head s_instances; //用于给定文件系统类型的超级快对象的指针
struct quota_info s_dquot; /* Diskquota specific options */磁盘限额的描述符
int s_frozen; //冻结文件系统时用的标致
wait_queue_head_t s_wait_unfrozen;//进程挂起的等待队列,直到文件系统被解冻
char s_id[32]; /* Informational name */包含超级快的块设备名称
//,为了效率起见,s_fs_info 字段所指向的数据被复制到内存
void *s_fs_info; /* Filesystem private info */指向特定文件系统的超级快信息的指针
fmode_t s_mode; //
/*
* The next field is for VFS *only*. No filesystems have any business
* even looking at it. You had been warned.
*/
struct mutex s_vfs_rename_mutex; /* Kludge */
/* Granularity of c/m/atime in ns.
Cannot be worse than a second */
u32 s_time_gran; //时间戳的粒度
/*
* Filesystem subtype. If non-empty the filesystem type field
* in /proc/mounts will be "type.subtype"
*/
char *s_subtype;
/*
* Saved mount options for lazy filesystems using
* generic_show_options()
*/
char *s_options;
};
/////////////////////
超级快的方法 结构体,与超级快有关的函数操作
struct super_operations {
//为索引节点(inode)i节点对象分配空间,包括具体文件系统的数据所需要的空间
struct inode *(*alloc_inode)(struct super_block *sb);
//撤销索引节点对象,包括具体文件系统的数据
void (*destroy_inode)(struct inode *);
void (*dirty_inode) (struct inode *);//索引节点修改时调用
int (*write_inode) (struct inode *, int);//用通过传递参数指定的索引节点对象的内容更新一个文件系统的索引节点,int flag参数标识是否应用同步
void (*drop_inode) (struct inode *);//在即将撤销索引节点时调用
void (*delete_inode) (struct inode *);//在必须撤销 节点时调用,删除内存中的VFS索引节点和磁盘上的文件数据及元数据
void (*put_super) (struct super_block *);//释放通过传递的参数指定的超级快对象(因为相应的文件系统被卸载)
void (*write_super) (struct super_block *);//用指定对象的内容更新文件系统的超级快
int (*sync_fs)(struct super_block *sb, int wait); //在清除文件系统来更新磁盘上的具体文件系统数据结构时调用( 由日志文件系统使用)
//阻塞对文件系统的修改并用指定对象的内容更新超级快,当文件系统被冻结时调用该方法,如逻辑卷管理器驱动程序LVM调用
void (*write_super_lockfs) (struct super_block *);
void (*unlockfs) (struct super_block *);//取消由write_super_lockfs超级快方法实现的对文件系统更新的阻塞
int (*statfs) (struct dentry *, struct kstatfs *);//将文件系统的统计信息返回,填写在buf缓冲区中
int (*remount_fs) (struct super_block *, int *, char *);//用新的选项重新安装文件系统
void (*clear_inode) (struct inode *);//当撤销磁盘索引节点执行具体文件系统操作时调用
void (*umount_begin) (struct super_block *);//中断一个安装操作,因为相应的卸载操作已经开始(只在网络文件系统中使用)
int (*show_options)(struct seq_file *, struct vfsmount *);//用来显示特定文件系统的选项
int (*show_stats)(struct seq_file *, struct vfsmount *);
#ifdef CONFIG_QUOTA
//限额系统使用该方法从文件中读取数据,该文件详细说明了所在文件系统的限制
ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
//限额系统使用该方法将数据写入文件中,该文件详细说明了所在文件系统的限制
ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
#endif
};
struct file_system_type {
const char *name; //文件系统的名字,这个名字唯一的标识一种文件系统
int fs_flags;
//这个函数非常重要,它VFS能够和底层文件系统交互的起始点,该函数是不能放在super_block结构中的,因为super_block是在get_sb执行之后才能建立的。get_sb从底层文件系统获取super_block的信息,是和底层文件系统相关的。*/
int (*get_sb) (struct file_system_type *, int,
const char *, void *, struct vfsmount *);
void (*kill_sb) (struct super_block *);
struct module *owner;//@owner是指向module的指针,仅当文件系统类型是以模块方式注册时,owner才有效。
struct file_system_type * next;//通过这个结构把所有已经注册的文件系统连接到file_systems
/*对于每一个mount的文件系统,系统都会为它创建一个super_block数据结构,该结构保存文件系统本省以及挂载点相关的信息。由于可以同时挂载多个同一文件系统类型的文件系统(比如/
和/home都挂载了ext3文件系统),因此同一个文件系统类型会对应多个super
block,@fs_supers就把这个文件系统类型对应的super block链接起来。 */
struct list_head fs_supers;
struct lock_class_key s_lock_key;
struct lock_class_key s_umount_key;
struct lock_class_key i_lock_key;
struct lock_class_key i_mutex_key;
struct lock_class_key i_mutex_dir_key;
struct lock_class_key i_alloc_sem_key;
};
常用标志的说明如下:
fs_flags:指明具体文件系统的一些特性,有关标志定义于fs.h中:
/* public flags for file_system_type */
#define FS_REQUIRES_DEV 1
#define FS_NO_DCACHE 2 /* Only dcache the necessary things. */
#define FS_NO_PRELIM 4 /* prevent preloading of dentries, even if
* FS_NO_DCACHE is not set. */
#define FS_SINGLE 8 /* Filesystem that can have only one superblock */
#define FS_NOMOUNT 16 /* Never mount from userland */
#define FS_LITTER 32 /* Keeps the tree in dcache */
#define FS_ODD_RENAME 32768 /* Temporary stuff; will go away as soon
* as nfs_rename() will be cleaned up */
(1) 有些虚拟的文件系统,如pipe、共享内存等,根本不允许由用户进程通过系统调用mount()来安装。这样的文件系统其fs_flags中的FS_NOMOUNT标志位为1。
(2) 一般的文件系统类型要求有物理的设备作为其物质基础,其fs_flags中的FS_REQUIRES_DEV标志位为1,这些文件系统如Ext2、Minix、ufs等。
(3)
有些虚拟文件系统在安装了同类型中的第一个“设备”,从而创建了其超级块的super_block数据结构,在安装同一类型中的其他设备时就共享已存在的super_block结构,而不再有自己的超级块结构。此时fs_flags中的FS_SINGLE标志位为1,表示整个文件系统只有一个超级块,而不像一般的文件系统类型那样,每个具体的设备上都有一个超级块。
·
owner:如果file_system_type所代表的文件系统是通过可安装模块实现的,则该指针指向代表着具体模块的module结构。如果文件系统是静态地链接到内核,则这个域为NULL。实际上,你只需要把这个域置为THIS_MODLUE
(这是个一个宏),它就能自动地完成上述工作。
· next:把所有的file_system_type结构链接成单项链表的链接指针,变量file_systems指向这个链表。这个链表是一个临界资源,受file_systems_lock自旋读写锁的保护
·
fs_supers:这个域是Linux2.4.10以后的内核版本中新增加的,这是一个双向链表。链表中的元素是超级块结构。如前说述,每个文件系统都有一个超级块,但有些文件系统可能被安装在不同的设备上,而且每个具体的设备都有一个超级块,这些超级块就形成一个双向链表
/////////////////////////////////////////////////////////////////////////////////////