上一篇介绍了文件打开open()操作,在open()操作中,已经获取到了文件描述符fd,fd本质就是file对象的下标,通过fd可以直接得到缓存中的file对象,通过file对象就可以进行文件的写操作write()。
继续阅读“012 Linux一次文件写过程wirte()”标签: 内核
03 ext2文件系统物理结构剖析
在说ext2物理结构之前,要先认祖归宗。
首先,大部分现代文件系统的祖先都能追溯到BSD FFS(Fast File System 1983年 BSD 4.2版本),所以对文件系统的介绍不可能忽略它。从40年后今天来看,BSD FFS的设计理念还有很多值得学习的地方,对于现代文件系统可以说是产生的深远的影响。在它的设计框架里,有一个超级块,一个块位图,一个inode位图和一些预分配的inode表。这种设计可在许多现代文件系统里找到影子。
继续阅读“03 ext2文件系统物理结构剖析”4.2BSD (August 1983) would take over two years to implement and contained several major overhauls. Before its official release came three intermediate versions: 4.1a from April 1982[13] incorporated a modified version of BBN’s preliminary TCP/IP implementation; 4.1b from June 1982 included the new Berkeley Fast File System, implemented by Marshall Kirk McKusick; and 4.1c in April 1983 was an interim release during the last few months of 4.2BSD’s development. Back at Bell Labs, 4.1cBSD became the basis of the 8th Edition of Research Unix, and a commercially supported version was available from mt Xinu.
From: History of the Berkeley Software Distribution – Wikipedia
02 ext2如何构造超级块super_block
上一篇介绍了ext2注册文件系统注册的流程,其中提到在注册文件系统时,给VFS传递了file_system_type结构体,在这个结构体中,包含了挂载函数指针ext2_mount(),用于挂载的回调操作。
在ext2_mount()函数实现中,调用了VFS的mount_bdev()来挂载块设备,这个mount_bdev()函数最后一个参数,是一个函数指针,VFS使用此函数完成超级块的构造和填充,而超级块是文件系统核心数据结构,它的构造是构建文件系统主要流程,本文就重点梳理一下超级块的构造,以下是mount_bdev()函数原型:
dentry *mount_bdev(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data,
int (*fill_super)(struct super_block *, void *, int));
继续阅读“02 ext2如何构造超级块super_block” 01 ext2注册/解注册文件系统
前面章节介绍了文件系统数据结构和基本流程,接下来以ext2文件系统为例,详细说明如何从头构建一个文件系统,主要包括:文件系统注册/解注册、文件系统挂载、超级块管理、inode管理等等。今天我们先来说一下注册和解注册文件系统。
文件系统属于内核模块,内核在加载这些模块时,会调用初始化init和退出exit函数,一般在这两个函数中完成注册和解注册动作,参考如下示意图。
继续阅读“01 ext2注册/解注册文件系统”011 Linux一次文件打开过程open()
前面介绍了文件系统的各种结构体,那么一次打开文件过程,需要和哪些结构体产生联系呢?要解决上面提出的问题,就要先搞清楚,函数是调用流程是怎样的,调用过程中串联了哪些数据结构,说起来也就是回答如下几个疑问:
- 打开文件的内核入口在哪里?
- 打开文件时,如何知道当前属于哪个文件系统呢?
- 如果文件已存在,那又如何获取目录项dentry和索引节点inode呢?
- 文件对象file是怎么构造的?
- 文件描述符是怎么产生的,又是如何跟file对象关联起来?
010 Linux文件系统数据结构详解:文件对象struct file
struct file是Linux文件系统中的一个重要数据结构,用于表示进程打开的文件,也就是文件对象,struct file是已打开的文件在内存中的表示,存储了与文件操作和状态相关的信息。
通过file对象就可以获取当前文件的目录项和索引节点,通过files_struct这个纽带,就把进程了和文件系统对接起来了。那么文件系统给进程呈现的是什么信息呢?
继续阅读“010 Linux文件系统数据结构详解:文件对象struct file”009 Linux文件系统数据结构详解:挂载点mount和vfsmount
前面介绍了超级块super_block、索引节点inode、目录项dentry等核心数据结构,接下来介绍文件系统挂载相关的mount和vfsmount结构体。
文件系统挂载就是将一个文件系统安装到全局文件结构树的一个分支上,文件系统挂载能力是VFS对外提供的统一的接口,实际挂载时会调用具体文件系统的实现(mount函数),这个具体实现逻辑是注册文件系统时,通过文件系统类型file_system_type结构体传递给VFS。挂载文件系统,VFS会回调具体文件系统的挂载函数mount(),mount()函数会构造超级块和根dentry,函数的返回值就是根dentry指针。
struct file_system_type {
const char *name;
int fs_flags;
int (*init_fs_context)(struct fs_context *);
const struct fs_parameter_spec *parameters;
struct dentry *(*mount) (struct file_system_type *, int,
const char *, void *);
void (*kill_sb) (struct super_block *);
struct module *owner;
struct file_system_type * next;
struct hlist_head fs_supers;
......
};
继续阅读“009 Linux文件系统数据结构详解:挂载点mount和vfsmount” 008 Linux文件系统数据结构详解:目录项dentry
前两篇博客看了超级块和索引节点的数据结构,接下来研究一下目录项dentry的结构。目录项设计的目的是构建完整的目录树,这样可以快速找到文件对应的inode,帮助VFS完成文件操作。具体过程如下:
用户程序在调用open()、stat()、chmod()等函数时,传递文件路径信息到VFS,VFS需要根据文件路径找到对应的inode,所以VFS用文件名和目录项缓存一层一层比对,直到找到对应的目录项,进而获取inode信息。如果在缓存中没有命中,VFS将会新创建文件的inode和对应的目录项,并且持久化到磁盘上。
继续阅读“008 Linux文件系统数据结构详解:目录项dentry”007 Linux文件系统数据结构详解:索引节点inode
上一篇讲了超级块,超级块存储了文件系统的基础信息,以及文件系统的控制信息。而今天介绍的索引节点数据结构,负责保存文件系统中实际文件一般信息,文件系统使用inode管理文件和目录。与超级块类似,索引节点也有三种形态:
- 持久化的索引节点
- 内存中构建的索引节点
- VFS提取的索引节点公共信息,构建出来的索引节点对象
006 Linux文件系统数据结构详解:超级块super_block
前面几篇文章,介绍了内核虚拟文件系统VFS的一些基本概念,今天开始正式详细介绍几个核心数据结构:超级块super_block、索引节点inode、目录项dentry、文件对象file、挂载点mount和vfsmount。对于文件系统来说,在谈论数据结构时,一般至少要关注三个方面:持久化的结构(磁盘上)、内存中的结构、以及VFS的结构。
Linux有一棵全局文件系统树,文件系统要被用户使用,必须先安装(挂载)到这棵树上。每一次安装被都会生成一个装载实例。每个文件系统装载后,都包含上述提到的四个对象:mount(含vfsmount)、超级块、根inode和根dentry,而文件对象file,是文件系统中文件被进程使用后产生的,可以认为是一个打开的文件。
继续阅读“006 Linux文件系统数据结构详解:超级块super_block”