【Linux文件系统入门】


前言

Linux经典语录:一切皆文件

文件系统的作用是用来管理磁盘上的文件(普通文件、目录、块设备、管道等),根据组织管理的方式不同,会有不同的文件系统。存在磁盘上的数据是持久化的,断电不丢失。


一、文件系统组成

Linux文件系统会给每个文件分配两个数据结构:索引节点和目录项。

1. 索引节点

索引节点(index node),即inode,用来记录文件metadata(元数据),是文件的唯一标识符,存在磁盘中。metadata主要为inode编号、文件大小、访问权限、stat时间、存储磁盘中的位置信息。
在这里插入图片描述

  • stat时间
struct timespec st_atim;  /* 上次访问(access time)的时间 */ 
  ○ 对文件进行读取的操作,cat、more等命令会改变,stat、ls不会影响
● struct timespec st_mtim;  /* 上次修改(modify time)的时间 */ 
  ○ 文件最后修改的时间,ls -al显示的时间,echo、vim操作会改变              
● struct timespec st_ctim;  /* 上次状态更改(change time)的时间 */
  ○ 改变文件的权限和属性的时候,chmod、chown

2. 目录项

目录项,即是dentry,用来记录文件名,索引节点指针、与其他目录项之间的层级关联关系。可以理解成tree显示目录层级关系。

区别于目录,目录项是内核管理的一个数据结构,占用了内存进行缓存;而目录则是一个文件,存储在磁盘中。

由于dentry是内核进行维护,则在系统启动的时候,就会对目录项进行init,读取各文件目录之间的层级关系。而当目录更新的时候,也会实时更新缓存。这样的好处是,查询目录不需要从磁盘读取,之间从缓存查询效率更高,特别有利于频繁查询。

3. 两者关系

在这里插入图片描述

磁盘挂载到某个路径下,才可访问;Linux系统启动的时候,文件系统会挂载在根目录/下,所以启动之后才可以对系统盘进行访问
磁盘读取的最小单位是扇区,一般为512B的大小

而文件系统读取的最小单位是一个逻辑块,一般为8个扇区,也即是4KB,这样的好处是提高磁盘的读写效率,一次性可以多读点数据出来。同时你要从磁盘读取10B的数据,也的最少读取4KB的数据出来,再去找那10B的数据。这里可以看出文件系统其实屏蔽了用户读写数据操作。
磁盘格式化,一般会分成三部分:超级块、索引节点、数据块;

  • 超级块区:存储文件系统的信息,块个数、块大小、空闲块等;磁盘挂载后,该块信息将加载进入内存
  • 索引节点区:存储索引节点;文件被访问时,加载进入内存,可以加速对文件的访问
  • 数据块区:存储文件

4. 文件链接

  • 硬链接
    多个文件名指向同一个inode号码;删除一个文件名,不影响另一个文件名;目录不允许硬连接;不同分区、不同硬盘不允许硬链接(inode编号可能重复)
root@CentOS7 lnDemo]# ln source source_ln
[root@CentOS7 lnDemo]# ls -ali
总用量 8
33575032 drwxr-xr-x. 2 root root  37 930 17:35 .
33574977 dr-xr-x---. 4 root root 161 930 17:34 ..
33575033 -rw-r--r--. 2 root root   7 930 17:31 source
33575033 -rw-r--r--. 2 root root   7 930 17:31 source_ln
[root@CentOS7 lnDemo]# stat source
  文件:"source"
  大小:7         	块:8          IO 块:4096   普通文件
设备:fd00h/64768d	Inode:33575033    硬链接:2
权限:(0644/-rw-r--r--)  Uid:(    0/    root)   Gid:(    0/    root)
环境:unconfined_u:object_r:admin_home_t:s0
最近访问:2020-09-30 17:34:54.975711266 +0800
最近更改:2020-09-30 17:31:49.124074625 +0800
最近改动:2020-09-30 17:35:05.665345071 +0800
创建时间:-
[root@CentOS7 lnDemo]# stat source_ln
  文件:"source_ln"
  大小:7         	块:8          IO 块:4096   普通文件
设备:fd00h/64768d	Inode:33575033    硬链接:2
权限:(0644/-rw-r--r--)  Uid:(    0/    root)   Gid:(    0/    root)
环境:unconfined_u:object_r:admin_home_t:s0
最近访问:2020-09-30 17:34:54.975711266 +0800
最近更改:2020-09-30 17:31:49.124074625 +0800
最近改动:2020-09-30 17:35:05.665345071 +0800
创建时间:-
  • 软连接
    当创建软连接的时候,linux确实已经创建了一个inode 和起对应来的data block,只不过,在data block存放的是字符串,字符串的内容则是 链接文件的地址。
[root@CentOS7 lnDemo]# ln -s source source_sln
[root@CentOS7 lnDemo]# ls
source  source_sln
[root@CentOS7 lnDemo]# ls -alt
总用量 4
drwxr-xr-x. 2 root root  38 930 18:08 .
lrwxrwxrwx. 1 root root   6 930 18:08 source_sln -> source
dr-xr-x---. 5 root root 172 930 17:55 ..
-rw-r--r--. 1 root root   7 930 17:31 source
[root@CentOS7 lnDemo]# ls -ailt
总用量 4
33575032 drwxr-xr-x. 2 root root  38 930 18:08 .
33575034 lrwxrwxrwx. 1 root root   6 930 18:08 source_sln -> source
33574977 dr-xr-x---. 5 root root 172 930 17:55 ..
33575033 -rw-r--r--. 1 root root   7 930 17:31 source

二、虚拟文件系统

1. VFS作用

虚拟文件系统(Virtual File System,VFS),是操作系统为了给用户提供的一个统一的接口,而引入的一个中间层,介于用户层和文件系统层之间。这样的好处是,用户不需要关心底层的文件系统是什么(EXT2、3、4,NFS),调用统一的接口对文件进行操作就行,而底层的逻辑则交给VFS去实现,对接不同的文件系统。

2. VFS实现

在这里插入图片描述

对文件的访问流程:用户空间调用库函数,内核空间进行系统调用,通过VFS的接口决定调用什么文件系统,然后将磁盘或者网络存储上的文件读入缓存buffer中,再依次返回到用户空间中

3. 文件描述符

在这里插入图片描述

用户要对文件进行write,首先需要open一个文件。在open一个文件的时候,操作系统其实为每个进程维护了一个打开文件表,而这个打开文件表就记录着对应打开文件的文件描述符,可以理解成对应打开文件标识或者编号。


三、用户空间文件系统(FUSE)

1. FUSE作用

用户空间文件系统(Filesystem in user space),也即是在用户空间实现的文件系统。常用的EXT4文件系统是内核空间的,我们通过系统调用write文件时,其底层通过VFS调用了EXT4文件系统的write实现,对磁盘中的数据进行写入。但是如果用户需要定制自己需求的一些文件系统功能,是不会对内核进行修改的,难度比较高。如果能在用户空间实现自己的文件系统,则可以定制自己的需求,而且不涉及内核,非常方便我们调试开发。

2. FUSE实现

在这里插入图片描述

首先,实现这个用户空间的文件系统,至少需要三个组件:

  • 内核模块的fuse:接收VFS的IO请求,并通过管道发送给用户态
  • 用户态的libfuse库:通过管道接收内核态的IO请求,并回调用户空间的文件系统
  • 用户空间的文件系统:用户空间的文件系统的具体实现

整体流程为:

  1. FUSE将磁盘挂载到/mnt/fuse目录下
  2. 用户使用FUSE文件系统,创建my.logwenj
  3. 调用系统open调用
  4. 经过VFS接口调用到FSUE处理
  5. 这里FUSE不是和内核文件系统一样,直接就调用内核create了,而是通过管道发送create的消息给后台的libfuse。
  6. libfuse创建的后台进程读取到消息,会调用对应的create函数,也即是libfuse中的low level层的接口
  7. 根据libfuse接口调用,回调用户空间文件系统FUSE的create函数,由用户空间的文件系统进行创建对应的文件
  8. 创建完成之后,再通过管道将消息传回给fuse.

3. FUSE 回调

static struct fuse_operations spdk_fuse_oper = {
	.mkdir		= fuse_mkdir, // make directories
	.opendir	= fuse_opendir,  // The  opendir()  function  opens a directory stream corresponding to the directory name, and returns a pointer to the directory stream.  The stream is positioned at the first entry in the directory.
	.getattr	= fuse_getattr,  // 获取文件、目录属性
	.readdir	= fuse_readdir,   // 读取目录,返回指向dirent结构体指针
	.mknod		= fuse_mknod,     // 建立一个目录项和一个特殊文件的对应索引节点
	.unlink		= fuse_unlink,    // 删除文件
	.truncate	= fuse_truncate,  // 重置文件大小
	.utimens	= fuse_utimens,   // 以纳秒级分辨率更改文件的访问和修改时间
	.open		= fuse_open,      // 打开文件
	.release	= fuse_release,    // 释放打开的文件,关闭文件描述符和内存解映射
	.read		= fuse_read,       // 读取打开文件的内容
	.write		= fuse_write,	   // 往打开的文件中写数据
	.flush		= fuse_flush,      // 刷新缓存数据,close前调用
	.fsync		= fuse_fsync,      // 同步文件内容
	.rename		= fuse_rename,      // 重命名文件
	.rmdir		= fuse_rmdir,  // remove empty directories
};

四、参考文档

深入理解基于Linux文件系统原理与实现
一口气搞懂「文件系统」,就靠这 25 张图了
5分钟搞懂用户空间文件系统FUSE工作原理
自制文件系统 — 02 FUSE 框架,开发者的福音
虚拟文件系统

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

自动驾驶小哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值