Linux 虚拟文件系统(二)--挂载文件系统

1. 前言

在上一篇文章中,我介绍了 VFS 中的重量级嘉宾 inode 结构体。inode 结构体是 VFS 的实现关键,但是俗语有云:"一个篱笆三个桩,一个好汉三个帮"。没有其他相关结构的帮助,仅凭 inode 结构体是没法实现 VFS 这么庞大的系统。

VFS 涉及的内核对象比较多,如果一股脑地搬出来,恐怕会杂乱无章,让人看了头大。一个文件系统要想注册到 VFS 进行使用,一般需要经历注册文件系统到内核、过载文件系统然后就可以对文件系统进行读写操作了。那么我们不妨按照这个顺序,将每个过程涉及到的数据结构一一呈现出来。如此一来,更具逻辑性。

2. 注册文件系统

文件系统实现两种注册进内核的方式,持久化编译到内核,内核的文件系统启动时便注册;另一种时将文件系统实现编译为模块,在相关内核载入内核时进行注册。

这两种注册方法本质上没有区别,都是使用 register_filesystem 函数向内核注册文件系统实现。只是注册时机不同而已。调用 register_filesystem 时,会将文件系统封装成一个file_system_type结构体,并使用结构体中的next字段将多个文件系统链接成一个链表。

下面是file_system_type结构体定义,在调用register_filesystem函数向内核注册文件系统时,内核会判断是否存在相同的name。如果相同则阻止注册。

arduino 复制代码
struct file_system_type { 
       const char *name; // 文件系统名称
       int fs_flags; 
       struct super_block *(*get_sb) (struct file_system_type *, int, 
                                         const char *, void *, struct vfsmount *); 
       // 获取超级块
       void (*kill_sb) (struct super_block *); 
       struct module *owner; 
       struct file_system_type * next; 
       struct list_head fs_supers; 
}; 

3. 挂载文件系统

类 UNIX 系统大多采用了单一文件系统的层次结构,新的文件系统可以集成到其中。用通俗点的话说就是只有一颗文件树,新的文件系统可以找这颗文件树任意一个叶子进行挂载。这里就产生了一个新的概念,挂载点。

如上图所示,是一颗文件树。其中相同颜色的是同一个文件系统。不难看出,图中所示共有三个文件系统。而其中/mnt和/mnt/usb则被称为挂载点,这是因为这些位置是装载文件系统的地方。

每个装载的文件系统都会产生一个vfsmount实例。vfsmount中包含指向文件系统的超级块和挂载点的目录。每挂载一个文件系统都在生成对应的vfsmount结构。

arduino 复制代码
struct vfsmount {
	struct dentry *mnt_root;	/* root of the mounted tree */
	struct super_block *mnt_sb;	/* pointer to superblock */
	int mnt_flags;
	struct mnt_idmap *mnt_idmap;
};

vfsmount并非挂载文件系统时需要在内存创建的唯一结构。超级块(superblock)是文件系统挂载的重要结构。文件系统的挂载开始于超级块的读取。

超级块是一个非常关键的数据结构,它存储了有关文件系统的整体信息和状态的元数据。超级块通常位于文件系统的开始部分,并且包含了文件系统的全局参数。

arduino 复制代码
struct super_block {
	struct list_head	s_list;		/* Keep this first */
	dev_t			s_dev;		/* search index; _not_ kdev_t */
	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; // 超级块支持的操作
	unsigned long		s_flags;
	unsigned long		s_iflags;	/* internal SB_I_* flags */
	unsigned long		s_magic;
	struct dentry		*s_root;  // 挂载的目录
	struct rw_semaphore	s_umount;
	int			s_count; // 引用计数
	atomic_t		s_active;
	struct hlist_bl_head	s_roots;	/* alternate root dentries for NFS */
	struct list_head	s_mounts;	/* list of mounts; _not_ for fs use */
	struct block_device	*s_bdev;
	struct hlist_node	s_instances;

	struct sb_writers	s_writers;

	void			*s_fs_info;	/* Filesystem private info */

	/* Granularity of c/m/atime in ns (cannot be worse than a second) */
	u32			s_time_gran;
	/* Time limits for c/m/atime in seconds */
	time64_t		   s_time_min;
	time64_t		   s_time_max;

	char			s_id[32];	/* Informational name */
	uuid_t			s_uuid;		/* UUID */

	unsigned int		s_max_links;

	const struct dentry_operations *s_d_op; /* default d_op for dentries */

	struct shrinker *s_shrink;	/* per-sb shrinker handle */

	/* Number of inodes with nlink == 0 but still referenced */
	atomic_long_t s_remove_count;

	/*
	 * Number of inode/mount/sb objects that are being watched, note that
	 * inodes objects are currently double-accounted.
	 */
	atomic_long_t s_fsnotify_connectors;

	/* Read-only state of the superblock is being changed */
	int s_readonly_remount;

	/* per-sb errseq_t for reporting writeback errors via syncfs */
	errseq_t s_wb_err;

	/* AIO completions deferred from interrupt context */
	struct workqueue_struct *s_dio_done_wq;
	struct hlist_head s_pins;

	/*
	 * The list_lru structure is essentially just a pointer to a table
	 * of per-node lru lists, each of which has its own spinlock.
	 * There is no need to put them into separate cachelines.
	 */
	struct list_lru		s_dentry_lru;
	struct list_lru		s_inode_lru;
	struct rcu_head		rcu;
	struct work_struct	destroy_work;

	struct list_head	s_inodes;	/* 文件系统所有的inode */

	spinlock_t		s_inode_wblist_lock;
	struct list_head	s_inodes_wb;	/* 等待写回的inode列表 */
};

超级块除了保存一些文件系统的基本信息之外,还维护了文件系统下所有关联 inode 结构。同时维护所有待写回的inode结构。

4. 参考资料

相关推荐
凤山老林3 分钟前
Spring Boot 集成 Apache CXF 发布与消费 SOAP WebService:WSDL、WS-Security
spring boot·后端·apache·webservice·soap·apache cxf
软件技术NINI9 分钟前
基于JavaWeb 汽车租聘
java·vue.js·spring boot·后端·python·毕业设计·毕设
yz_aiks12 分钟前
RestTemplate 废弃后迁移 RestClient 实战:Spring Boot 4.2 升级指南
java·spring boot·后端·微服务·restclient
金銀銅鐵9 小时前
[Java] 用 GUI 展示 EnumSet 增减元素时的内部变化(上)
java·后端·ai编程
念何架构之路10 小时前
go-grpc设计思想
开发语言·后端·golang
system_error_x10 小时前
SpringBoot 集成 Thymeleaf 简洁入门
java·spring boot·后端
步行cgn12 小时前
Spring MVC 视图机制的核心接口与类
java·开发语言·后端·spring·mvc
码事漫谈13 小时前
AI 读你的提示词,其实很没耐心
后端
用户83562907805114 小时前
如何使用 Python 格式化 Excel 单元格中的长文本
后端·python
我命由我1234514 小时前
Python 开发 - Python 的 pathlib
java·开发语言·后端·python·学习·java-ee·学习方法