通俗易懂!快速了解虚拟文件系统(VFS)
发布时间 - 2025-07-14 00:00:00 点击率:次前言
为什么 Linux 内核支持如此多种类的文件系统,并且都能顺利挂载呢?为什么可以在系统中直接挂载其他文件系统,甚至将 Windows 下的文件夹挂载到 Linux 上?Linux 的虚拟文件系统(VFS)为何如此强大?这都归功于其精妙的数据结构设计。似乎有个说法,Linux 有什么解决不了的问题?就加一层。
VFS 是什么?虚拟文件系统,简称 VFS(Virtual Filesystem),是内核中的一个软件层。
VFS 的作用可以概括为两点:
- 处理与 Unix 标准文件系统相关的所有系统调用。
- 为各种文件系统提供一个通用的接口。
VFS 支持的文件系统类型如下列出一些常见的文件系统类型,本文暂不进行详细分析。
- 磁盘文件系统:ext2,ext3,...
- 网络文件系统类型:nfs,smbfs,...
- 特殊文件系统:tmpfs,ramfs,...
- 伪文件系统:procfs,sysfs,...
VFS 的设计思想 VFS 设计的初衷是支持所有的文件系统,因此其设计思想是采用面向对象的方式,设计一个通用的文件模型。尽管出于效率考虑,VFS 是用 C 语言编写的。在通用文件系统模型中,每个目录也被视为一个文件,可以包含若干文件和其他子目录。因此,Linux 有一句经典的话:一切皆文件。
关键数据结构介绍 Linux VFS 抽象出四种类型的数据结构,以实现将不同类型的文件系统挂载到目录结构中。
超级块对象 对于磁盘类文件系统,超级块是存放在磁盘上的文件系统控制块,里面存放已安装文件系统的相关信息。换句话说,一个超级块描述了一个具体文件系统的信息,其中的信息非常重要,也称为元数据。与普通的文件数据相比,元数据的丢失会损坏整个文件系统,导致无法挂载等问题。当然,不仅超级块,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];
};数据结构组织关系图
# node.js
# linux
# windows
# 为什么
# red
# 面向对象
# Filesystem
# 数据结构
# 接口
# 对象
# unix
# 文件系统
# 放在
# 链表
# 相关信息
# 自己的
# 的是
# 设计思想
# 信号量
# 有什么
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
Laravel如何设置定时任务(Cron Job)_Laravel调度器与任务计划配置
微信小程序 require机制详解及实例代码
JS去除重复并统计数量的实现方法
javascript中数组(Array)对象和字符串(String)对象的常用方法总结
如何在IIS7上新建站点并设置安全权限?
用v-html解决Vue.js渲染中html标签不被解析的问题
Laravel怎么实现一对多关联查询_Laravel Eloquent模型关系定义与预加载【实战】
今日头条AI怎样推荐抢票工具_今日头条AI抢票工具推荐算法与筛选【技巧】
如何确保西部建站助手FTP传输的安全性?
手机网站制作平台,手机靓号代理商怎么制作属于自己的手机靓号网站?
教你用AI将一段旋律扩展成一首完整的曲子
iOS验证手机号的正则表达式
如何在阿里云高效完成企业建站全流程?
Laravel Pest测试框架怎么用_从PHPUnit转向Pest的Laravel测试教程
免费制作统计图的网站有哪些,如何看待现如今年轻人买房难的情况?
Laravel如何与Vue.js集成_Laravel + Vue前后端分离项目搭建指南
免费网站制作appp,免费制作app哪个平台好?
怎么制作一个起泡网,水泡粪全漏粪育肥舍冬季氨气超过25ppm,可以有哪些措施降低舍内氨气水平?
敲碗10年!Mac系列传将迎来「触控与联网」双革新
Laravel如何使用API Resources格式化JSON响应_Laravel数据资源封装与格式化输出
微信小程序 wx.uploadFile无法上传解决办法
Laravel如何实现登录错误次数限制_Laravel自带LoginThrottles限流配置【方法】
高端网站建设与定制开发一站式解决方案 中企动力
如何基于云服务器快速搭建个人网站?
php做exe能调用系统命令吗_执行cmd指令实现方式【详解】
北京网站制作的公司有哪些,北京白云观官方网站?
Laravel怎么返回JSON格式数据_Laravel API资源Response响应格式化【技巧】
微信小程序 canvas开发实例及注意事项
如何在阿里云完成域名注册与建站?
Laravel怎么配置不同环境的数据库_Laravel本地测试与生产环境动态切换【方法】
JavaScript如何操作视频_媒体API怎么控制播放
利用 Google AI 进行 YouTube 视频 SEO 描述优化
详解CentOS6.5 安装 MySQL5.1.71的方法
google浏览器怎么清理缓存_谷歌浏览器清除缓存加速详细步骤
Laravel如何从数据库删除数据_Laravel destroy和delete方法区别
mc皮肤壁纸制作器,苹果平板怎么设置自己想要的壁纸我的世界?
Python自动化办公教程_ExcelWordPDF批量处理案例
海南网站制作公司有哪些,海口网是哪家的?
Laravel怎么实现模型属性转换Casting_Laravel自动将JSON字段转为数组【技巧】
如何在万网ECS上快速搭建专属网站?
Laravel Eloquent性能优化技巧_Laravel N+1查询问题解决
详解免费开源的DotNet二维码操作组件ThoughtWorks.QRCode(.NET组件介绍之四)
电商网站制作价格怎么算,网上拍卖流程以及规则?
JS碰撞运动实现方法详解
香港服务器建站指南:免备案优势与SEO优化技巧全解析
Laravel如何实现RSS订阅源功能_Laravel动态生成网站XML格式订阅内容【教程】
谷歌Google入口永久地址_Google搜索引擎官网首页永久入口
如何正确下载安装西数主机建站助手?
浅析上传头像示例及其注意事项
Laravel如何使用Gate和Policy进行授权?(权限控制)


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];
};