【推荐阅读】
在Linux中,“万物兼文件”,我们知道在linux下面有很多文件系统,如EXT/2/3/4,XFS等,为了很好的支持各种类型的文件系统,Linux抽象了一层虚拟文件系统层,用于更加灵活的适配各种具体的文件系统实现。其基本架构如下:
虚拟文件系统架构
可以看到所有的虚拟文件系统操作都必须在内核态执行,这是由于对于系统存储及外部设备的访问极其复杂,这部分的操作不能交给用户去操作,否则系统会非常不稳定。
文件系统类型
- 基于磁盘的文件系统
在非易失介质存储存储文件的经典方法,也就是为我们所熟知的各类文件系统,注入EXT2/3/4, FAT等 - 虚拟文件系统
在内核中生成,是一种使用用户应用程序与用户通信的方法,最为人所知的就是proc文件系统,其不需要与任何种类的硬件上存储信息,所有的信息都存储在内存中,伴随着进程而消亡 - 网络文件系统
这种文件系统可以访问其他计算机上的数据,本机不会陷入内核态,所有的请求会发送到其他机器执行,因此网络文件系统一般会以FUSE的形式挂载。
通用文件系统
虚拟文件系统定义了一些了方法和抽象以及文件系统中对象(或文件)的统一视图,但是在不同的实现中,会截然不同,其提供的是一个通用的全集,其提供的许多操作在某些子系统中并不需要,比如proc系统中的write_page操作。
在处理文件时,内核空间和用户空间使用的对象是不同的,在用户空间一个文件有一个"文件描述符"标识,是一个整数,也就是我们经常说的FD,只在一个进程内部有效,两个不同进程之间可以使用同一个FD;而FD对应的内核空间的数据结构是struct file,其主要的成员为address_space,address_space是真正与底层设备交互数据结构,而另外一个管理文件元信息的数据结构是inode,其存储着文件的链接,访问时间,版本,对应的后端设备,所在的超级块等等元信息,但是不包括文件名,文件名存储在struct dentry中,这是由于文件名是用于索引及管理inode的,而dentry就是用于管理inode的,而dentry则通过super_block索引。
下面我们就来具体讨论一下具体的各个结构及他们的关系,并讨论一下在linux中打开一个文件到写入具体经历了哪些事情。
VFS结构
inode
inode用于管理文件的元数据信息,包括权限信息,访问信息,链接信息,存储设备信息等, 对应的操作主要包括链接、权限、,其数据结构如下:
/*
* Keep mostly read-only and often accessed (especially for
* the RCU path lookup and 'stat' data) fields at the beginning
* of the 'struct inode'
*/
struct inode {
...
const struct inode_operations *i_op; // inode的操作,与具体的文件系统相关
struct super_block *i_sb; // 超级块
struct address_space *i_mapping; // 地址空间,真正的与设备交互模块
...
/* Stat data, not accessed from path walking */
unsigned long i_ino; // inode 编号
/*
* Filesystems may only read i_nlink directly. They shall use the
* following functions for modification:
*
* (set|clear|inc|drop)_nlink
* inode_(inc|dec)_link_count
*/
union {
const unsigned int i_nlink;
unsigned int __i_nlink;
};
dev_t i_rdev;
loff_t i_size;
struct timespec64 i_atime; // 最后访问时间
struct timespec64 i_mtime; // 最后修改时间
struct timespec64 i_ctime; // 创建时间
spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */
unsigned short i_bytes; // 文件大小字节数
u8 i_blkbits; // 文件大小对应的块长度
u8 i_write_hint;
blkcnt_t i_blocks; // 文件长度 / 块长度
#ifdef __NEED_I_SIZE_ORDERED
seqcount_t i_size_seqcount;
#endif
/* Misc */
unsigned long i_state;
struct rw_semaphore i_rwsem;
unsigned long dirtied_when; /* jiffies of first dirtying */
unsigned long dirtied_time_when;
struct hlist_node i_hash;
struct list_head i_io_list; /* backing dev IO list */
#ifdef CONFIG_CGROUP_WRITEBACK
struct bdi_writeback *i_wb; /* the associated cgroup wb */
/* foreign inode detection, see wbc_detach_inode() */
int i_wb_frn_winner;
u16 i_wb_frn_avg_time;
u16 i_wb_frn_history;
#endif
struct list_head i_lru; /* inode LRU list */
struct list_head i_sb_list;
struct list_head i_wb_list; /* backing dev writeback list */
union {
struct hlist_head i_dentry; // 一个inode可能被多个dentry使用(link)
struct rcu_head i_rcu;
};
atomic64_t 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; // 字符设备
char *i_link; // 不知道是啥
unsigned i_dir_seq; // 不知道是啥
};
__u32 i_generation;
#ifdef CONFIG_FSNOTIFY
__u32 i_fsnotify_mask; /* all e