linux文件系统三 VFS数据结构体剖析

一、结构体种类:

1、超级块对象struct super_block *sb:  

  超级块代表了整个文件系统,超级块是文件系统的控制块,有整个文件系统信息,一个文件系统所有的inode

都要连接到超级块上,可以说,一个超级块就代表了一个文件系统。每次一个实际的文件系统被安装时,内核会从

磁盘的特定位置读取一些控制信息来填充内存中的超级块对象。super_block定义在include/linux/fs.h里:

struct super_block {
	struct list_head	s_list;		    /*指向超级块链表的指针*/
	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;     /*super_block的操作函数集合*/
	const struct dquot_operations	*dq_op;    /*文件系统的限额操作函数集合*/

	unsigned long		s_flags;            /*文件系统的超级块的状态位*/  
	struct dentry		*s_root;            /*指向根目录的dentry结构体*/
	int			s_count;            /*引用计数*/
	char s_id[32];				    /* 文件系统的名字 */
	void 			*s_fs_info;	    /* 文件系统的私有信息指针 */
	struct list_head	s_inodes;	    /* 文件系统的inode结构体都在这个队列上 */
        //......
};

  super block操作函数接口:

struct super_operations {
   	struct inode *(*alloc_inode)(struct super_block *sb);
	void (*destroy_inode)(struct inode *);

   	void (*dirty_inode) (struct inode *, int flags);
	int (*write_inode) (struct inode *, struct writeback_control *wbc);

#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);
	struct dquot **(*get_dquots)(struct inode *);
#endif
//......
}

2、索引节点对象struct inode * inode:

  索引节点对象存储了文件的相关信息,代表了存储设备上的一个实际的物理文件。当一个 文件首次被访问时,

内核会在内存中组装相应的索引节点对象,以便向内核提供对一个文件进行操 作时所必需的全部信息;这些信息

一部分存储在磁盘特定位置,另外一部分是在加载时动态填充的。

struct inode {
	umode_t			i_mode;    /*访问权限控制*/
	kuid_t			i_uid;     /*使用者id*/
	kgid_t			i_gid;     /*使用者id组*/
	unsigned int		i_flags;   /*文件系统标志*/

	const struct inode_operations	*i_op;    /*inode 操作接口*/
	struct super_block	*i_sb;            /*相关的超级块*/

	/* Stat data, not accessed from path walking */
	unsigned long		i_ino;      /*节点号*/
	loff_t			i_size;     /*以字节为单位的文件大小*/
	struct timespec		i_atime;    /*最后访问时间*/
	struct timespec		i_mtime;    /*最后修改(modify)时间*/
	struct timespec		i_ctime;    /*最后改变(change)时间*/
    unsigned long		dirtied_when;	/* 首次修改时间 */
	spinlock_t		i_lock;	        /*文件的块数*/
	unsigned long		i_state;      /*状态标志*/

	u64			i_version;      /*版本号*/
	atomic_t		i_count;        /*引用记数*/
	atomic_t		i_dio_count;
	atomic_t		i_writecount;   /*写者记数*/

	const struct file_operations	*i_fop;	/* 索引节点操作 */
};

3、文件对象struct file *file:

  struct file结构体定义在include/linux/fs.h中定义。文件结构体代表一个打开的文件,系统中的每个打开的文件

在内核空间都有一个关联的 struct file。它由内核在打开文件时创建,并传递给在文件上进行操作的任何函数。

在文件的所有实例都关闭后,内核释放这个数据结构。一个文件对应的文件对象可能不是惟一的,但是其对应的

索引节点和 目录项对象无疑是惟一的。在内核创建和驱动源码中,struct file的指针通常被命名为file或filp。

struct file {

	struct path		f_path;         /* 包含dentry和mnt两个成员,用于确定文件路径 */
	const struct file_operations	*f_op;  /* 与该文件相关联的操作函数 */
    
	atomic_long_t		f_count;        /* 文件的引用计数(有多少进程打开该文件) */
	unsigned int 		f_flags;        /* 这些是文件标志, 例如 O_RDONLY, O_NONBLOCK, 和 O_SYNC */
	fmode_t			f_mode;         /* 读写模式:open的mod_t mode参数 */
	loff_t			f_pos;          /* 该文件在当前进程中的文件偏移量 */
	struct fown_struct	f_owner;        /* 该结构的作用是通过信号进行I/O时间通知的数据*/
    
} __attribute__((aligned(4)));

  对应的函数操作接口:

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 (*read_iter) (struct kiocb *, struct iov_iter *);
	ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
	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 *);
    //......
}

4、struct dentry 目录项:

//kernel-4.9/include/linux/dcache.h
struct dentry {
	unsigned int d_flags;		    /* 目录项标志 */
	struct hlist_bl_node d_hash;	    /* 散列表表项的指针 */
	struct dentry *d_parent;	    /* 父目录的目录项对象 */
	struct qstr d_name;                 /* 文件名 */
	struct inode *d_inode;		    /* 与文件名关联的索引节点 */
	unsigned char d_iname[DNAME_INLINE_LEN];	/* 存放短文件名 */
	const struct dentry_operations *d_op;           /* 目录项操作方法 */
	struct super_block *d_sb;	                /* 文件的超级块对象 */
	void *d_fsdata;			                /* 与文件系统相关的数据 */
	struct list_head d_subdirs;	                /* 子目录 */
    //......
};

  对应的函数操作接口:

struct dentry_operations {
	int (*d_compare)(const struct dentry *,
			unsigned int, const char *, const struct qstr *);
	int (*d_delete)(const struct dentry *);
	int (*d_init)(struct dentry *);
	void (*d_release)(struct dentry *);
	void (*d_prune)(struct dentry *);
	void (*d_iput)(struct dentry *, struct inode *);
	char *(*d_dname)(struct dentry *, char *, int);
	struct vfsmount *(*d_automount)(struct path *);
//......
} ____cacheline_aligned;

二、数据结构之间的关系:

  在进程中打开一个文件F,实际上就是要在内存中建立的dentry和inode结构,并让它们与进程结构联系来,

把VFS中定义的接口给接起来,可以用如下两图表明:

作者:frank_zyp 
您的支持是对博主最大的鼓励,感谢您的认真阅读。 
本文无所谓版权,欢迎转载。

发布了59 篇原创文章 · 获赞 80 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/frank_zyp/article/details/88714591