百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

通俗易懂!快速了解虚拟文件系统(VFS)

liebian365 2024-11-05 11:50 13 浏览 0 评论

前言

为什么 Linux 内核的文件系统类型那么多,都能挂载上呢?为什么系统里可以直接 mount 其他文件系统呢?甚至能把 windows 下的文件夹挂载到 windows 上,为什么 Linux 的虚拟文件系统这么强大?这得益于它的数据结构设计得十分精妙。好像听过,Linux 有什么解决不了的?加一层。

VFS 是什么

虚拟文件系统,简称 VFS(Virtual Filesystem),是一个内核软件层。

VFS 的作用

概括地讲,VFS 有两个作用:

  1. 处理与 Unix 标准文件系统相关的所有系统调用
  2. 为各种文件系统提供一个通用的接口

VFS 支持的文件系统类型

以下列出以下常见的文件系统类型,本文暂时不对其进行详细分析。

  1. 磁盘文件系统
    ext2,ext3,···
  2. 网络文件系统类型
    nfs,smbfs,···
  3. 特殊文件系统
    tmpfs,ramfs,···
  4. 伪文件系统
    procfs,sysfs,···

VFS 的设计思想

VFS 设计的初衷就是要支持所有的文件系统,所以它的设计思想其实就是以面向对象的方式,设计一个通用的文件模型,出于效率考虑,VFS 还是 C 语言写的。
在通用文件系统模型中,每个目录也被当作一个文件,可以包含若干文件和其他的子目录。因此,Linux 有一句经典的话:一切皆文件。

关键数据结构介绍

Linux VFS 抽象出 4 种类型的数据结构,实现将不同类型的文件系统挂载到目录结构中。

超级块对象

对于磁盘类文件系统,超级块是存放在磁盘上的文件系统控制块,里面存放已安装文件系统的有关信息,换句话说,一个超级块描述了一个具体的文件系统信息,里面的信息十分重要,也叫元数据,与普通的文件数据相比,元数据丢失会损坏整个文件系统,导致无法挂载之类的问题。当然,不仅超级块,inode上也有很多元数据。

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;  //指向文件系统的file_system_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_magic; //文件系统的魔术字
  struct dentry	*s_root;  //目录登录点
  struct rw_semaphore	s_umount; //卸载信号量
  int	s_count; //超级块引用计数
  atomic_t s_active; //活动引用记数
  #ifdef CONFIG_SECURITY
  void *s_security; //安全模块
  #endif
  const struct xattr_handler **s_xattr;
  struct list_head s_inodes;	//把所有索引对象链接在一起,存放的是头结点
  struct hlist_bl_head s_anon;	//匿名目录项
  struct list_head s_mounts;	/* list of mounts; _not_ for fs use */
  struct block_device	*s_bdev; //相关的块设备
  struct backing_dev_info *s_bdi;
  struct mtd_info	*s_mtd;
  struct hlist_node	s_instances; //该类型文件系统
  unsigned int		s_quota_types;	/* Bitmask of supported quota types */
  struct quota_info	s_dquot;//限额相关选项
  struct sb_writers	s_writers;
  char s_id[32]; /* Informational name */
  u8 s_uuid[16]; /* UUID */
  void *s_fs_info; /* Filesystem private info */
  unsigned int s_max_links;
  fmode_t s_mode;
  u32	s_time_gran;
  struct mutex s_vfs_rename_mutex;	/* Kludge */
  char *s_subtype;
  char __rcu *s_options;
  const struct dentry_operations *s_d_op; /* default d_op for dentries */
  int cleancache_poolid;
  struct shrinker s_shrink;	/* per-sb shrinker handle */
  atomic_long_t s_remove_count;
  int s_readonly_remount;
  struct workqueue_struct *s_dio_done_wq;
  struct hlist_head s_pins;
  struct list_lru	s_dentry_lru ____cacheline_aligned_in_smp;
  struct list_lru	s_inode_lru ____cacheline_aligned_in_smp;
  struct rcu_head	rcu;
  int s_stack_depth;
};

索引节点对象(inode)

索引节点存放关于具体文件的一般信息。对于磁盘类文件系统,索引节点也是存放在磁盘上的文件控制块。每个索引节点都有一个索引节点号,这个节点号唯一地标识了文件系统中的文件。

struct inode {
 umode_t i_mode; //访问权限控制
 unsigned short i_opflags;
 kuid_t i_uid; //使用者的id
 kgid_t i_gid; //使用组id
	 unsigned int i_flags; //文件系统标志
#ifdef CONFIG_FS_POSIX_ACL
	 struct posix_acl *i_acl;
	 struct posix_acl *i_default_acl;
#endif
	 const struct inode_operations	*i_op; //指向索引结点操作结构体的指针
	 struct super_block *i_sb; //指向inode所属文件系统的超级块的指针
	 struct address_space *i_mapping; //相关的地址映射
#ifdef CONFIG_SECURITY
	 void *i_security; //安全模块
#endif
	 unsigned long	i_ino; //索引结点号。通过ls -i命令可以查看文件的索引节点号
	 union {
		  const unsigned int i_nlink; //硬链接数
		  unsigned int __i_nlink;
 };
	dev_t	i_rdev; //实际设备标识符号
	loff_t i_size; //以字节为单位
	struct timespec i_atime; //最后访问时间
	struct timespec i_mtime; //最后修改时间
	struct timespec i_ctime; //最后改变时间
	spinlock_t i_lock;	/* i_blocks, i_bytes, maybe i_size */
	unsigned short i_bytes; //使用的字节数
	unsigned int i_blkbits; 以位为单位的块大小
	blkcnt_t i_blocks; //文件的块数
#ifdef __NEED_I_SIZE_ORDERED
	seqcount_t i_size_seqcount;
#endif
	unsigned long i_state; //状态标志
	struct mutex i_mutex;
	unsigned long dirtied_when;	//首次修改时间
	unsigned long dirtied_time_when;
	struct hlist_node i_hash; //散列表
	struct list_head i_wb_list;	/* backing dev IO list */
	struct list_head i_lru;		/* inode LRU list */
	struct list_head i_sb_list; //链接一个文件系统中所有inode的链表
	union {
		 struct hlist_head i_dentry; //目录项链表
		 struct rcu_head	 i_rcu;
};
u64 i_version; //版本号
	atomic_t i_count; //引用计数
	atomic_t i_dio_count;
	atomic_t i_writecount; //写者计数
#ifdef CONFIG_IMA
	atomic_t i_readcount; /* struct files open RO */
#endif
	const struct file_operations *i_fop;	/* former ->i_op->default_file_ops */
	struct file_lock_context *i_flctx;
	struct address_space i_data; //设备地址映射
	struct list_head i_devices; //块设备链表
	union {
		 struct pipe_inode_info	*i_pipe; //管道信息
		 struct block_device *i_bdev; //块设备
		 struct cdev  *i_cdev; //字符设备
};
__u32	i_generation; //索引节点版本号
#ifdef CONFIG_FSNOTIFY
 __u32	i_fsnotify_mask; /* all events this inode cares about */
	 struct hlist_head i_fsnotify_marks;
#endif
	void *i_private; /* fs or device private pointer */
};

目录项对象(dentry)

存放 dentry 与对应文件链接的有关信息,每个 dentry 代表路径中的一个特定部分,每个磁盘类文件系统以自己的方式将目录项信息存放在磁盘上。

struct dentry {
 /* RCU lookup touched fields */
	unsigned int d_flags; /* protected by d_lock */
	seqcount_t d_seq; /* per dentry seqlock */
	struct hlist_bl_node d_hash; /* lookup hash list */
	struct dentry *d_parent; /* parent directory */
	struct qstr d_name;
	struct inode *d_inode; /* Where the name belongs to - NULL is negative */
	unsigned char d_iname[DNAME_INLINE_LEN]; /* small names */
	/* Ref lookup also touches following */
	struct lockref d_lockref;	/* per-dentry lock and refcount */
	const struct dentry_operations *d_op;
	struct super_block *d_sb;	/* The root of the dentry tree */
	unsigned long d_time; /* used by d_revalidate */
	void *d_fsdata;	/* fs-specific data */
	struct list_head d_lru; /* LRU list */
	struct list_head d_child;	/* child of parent list */
	struct list_head d_subdirs;	/* our children */
	/*
 * d_alias and d_rcu can share memory
 */
	union {
		 struct hlist_node d_alias; /* inode alias list */
	 	 struct rcu_head d_rcu;
} d_u;
};

文件对象(file)

存放被打开文件与进程间交互的信息,这类信息仅当进程访问文件期间存放在内存中。

struct file {
 union {
		  struct llist_node fu_llist; //每个文件系统中被打开的文件都会形成一个双链表
		  struct rcu_head  fu_rcuhead;
 } f_u;
	struct path f_path;
	struct inode *f_inode;	/* cached value */
	const struct file_operations *f_op; //指向文件操作表的指针
	spinlock_t f_lock;
	atomic_long_t	f_count; //文件对象的使用计数
	unsigned int  f_flags; //打开文件时所指定的标志
	fmode_t	f_mode; //文件的访问模式
	struct mutex f_pos_lock;
	loff_t f_pos; //文件当前的位移量
	struct fown_struct f_owner;
	const struct cred *f_cred;
	struct file_ra_state	f_ra; //预读状态
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;
	 struct list_head	f_tfile_llink;
#endif /* #ifdef CONFIG_EPOLL */
	struct address_space	*f_mapping;  //页缓存映射
} __attribute__((aligned(4)));	/* lest something weird decides that 2 is OK */
struct file_handle {
__u32 handle_bytes;
	int handle_type;
	/* file identifier */
	unsigned char f_handle[0];
};

数据结构组织关系图

相关推荐

4万多吨豪华游轮遇险 竟是因为这个原因……

(观察者网讯)4.7万吨豪华游轮搁浅,竟是因为油量太低?据观察者网此前报道,挪威游轮“维京天空”号上周六(23日)在挪威近海发生引擎故障搁浅。船上载有1300多人,其中28人受伤住院。经过数天的调...

“菜鸟黑客”必用兵器之“渗透测试篇二”

"菜鸟黑客"必用兵器之"渗透测试篇二"上篇文章主要针对伙伴们对"渗透测试"应该如何学习?"渗透测试"的基本流程?本篇文章继续上次的分享,接着介绍一下黑客们常用的渗透测试工具有哪些?以及用实验环境让大家...

科幻春晚丨《震动羽翼说“Hello”》两万年星间飞行,探测器对地球的最终告白

作者|藤井太洋译者|祝力新【编者按】2021年科幻春晚的最后一篇小说,来自大家喜爱的日本科幻作家藤井太洋。小说将视角放在一颗太空探测器上,延续了他一贯的浪漫风格。...

麦子陪你做作业(二):KEGG通路数据库的正确打开姿势

作者:麦子KEGG是通路数据库中最庞大的,涵盖基因组网络信息,主要注释基因的功能和调控关系。当我们选到了合适的候选分子,单变量研究也已做完,接着研究机制的时便可使用到它。你需要了解你的分子目前已有哪些...

知存科技王绍迪:突破存储墙瓶颈,详解存算一体架构优势

智东西(公众号:zhidxcom)编辑|韦世玮智东西6月5日消息,近日,在落幕不久的GTIC2021嵌入式AI创新峰会上,知存科技CEO王绍迪博士以《存算一体AI芯片:AIoT设备的算力新选择》...

每日新闻播报(September 14)_每日新闻播报英文

AnOscarstatuestandscoveredwithplasticduringpreparationsleadinguptothe87thAcademyAward...

香港新巴城巴开放实时到站数据 供科技界研发使用

中新网3月22日电据香港《明报》报道,香港特区政府致力推动智慧城市,鼓励公私营机构开放数据,以便科技界研发使用。香港运输署21日与新巴及城巴(两巴)公司签署谅解备忘录,两巴将于2019年第3季度,开...

5款不容错过的APP: Red Bull Alert,Flipagram,WifiMapper

本周有不少非常出色的app推出,鸵鸟电台做了一个小合集。亮相本周榜单的有WifiMapper's安卓版的app,其中包含了RedBull的一款新型闹钟,还有一款可爱的怪物主题益智游戏。一起来看看我...

Qt动画效果展示_qt显示图片

今天在这篇博文中,主要实践Qt动画,做一个实例来讲解Qt动画使用,其界面如下图所示(由于没有录制为gif动画图片,所以请各位下载查看效果):该程序使用应用程序单窗口,主窗口继承于QMainWindow...

如何从0到1设计实现一门自己的脚本语言

作者:dong...

三年级语文上册 仿写句子 需要的直接下载打印吧

描写秋天的好句好段1.秋天来了,山野变成了美丽的图画。苹果露出红红的脸庞,梨树挂起金黄的灯笼,高粱举起了燃烧的火把。大雁在天空一会儿写“人”字,一会儿写“一”字。2.花园里,菊花争奇斗艳,红的似火,粉...

C++|那些一看就很简洁、优雅、经典的小代码段

目录0等概率随机洗牌:1大小写转换2字符串复制...

二年级上册语文必考句子仿写,家长打印,孩子照着练

二年级上册语文必考句子仿写,家长打印,孩子照着练。具体如下:...

一年级语文上 句子专项练习(可打印)

...

亲自上阵!C++ 大佬深度“剧透”:C++26 将如何在代码生成上对抗 Rust?

...

取消回复欢迎 发表评论: