linux内核开文件系统,内核必须懂(二): Linux文件系统初探

目录

前言

文件系统结构

新建文件和inode

文件创建过程

inode解析

打开文件

参考

最后

前言

这次来说文件系统. 文件系统是非常重要的, 提高磁盘使用率, 减小磁盘磨损等等都是文件系统要解决的问题. 市面上的文件系统也是数不胜数, 比较常用的像ext4, xfs以及ntfs等等, 国内的像鹅厂的tfs, 然后还有sun号称"last word in file system"的ZFS, 学习ZFS而来的btrfs.

下面上一张Linux文件系统组件的体系结构图, 是我整合了多方文献并结合自己的经验画出来的. 可以看出, 最重要的就是vfs, 正是因为它, 才让Linux可以同时支持多种的文件系统. 举个例子, 比如你装了双系统mint+windows, 在mint中, 你可以看到windows的ntfs磁盘, 但是返回了windows, 你就看不到mint的磁盘了.

AAffA0nNPuCLAAAAAElFTkSuQmCC

那Linux支持哪些文件系统呢? 来到源码的fs文件夹, Linux支持的文件系统可多了去了, 注意看蓝色的.

AAffA0nNPuCLAAAAAElFTkSuQmCC

文件系统结构

磁盘扇区什么的就不多说了. 也许会出一篇谈存储介质的文章, 说说ssd结构啥的. 直接跳过硬件从文件系统结构开始. 注意, 我说的是通用模型, 每个fs的具体实现有差异, 而且差异蛮大的. ext家族是Linux默认的fs了, 事实上ext2/ext3和ext4差异也很大.

superblock: 记录此fs的整体信息, 包括inode/block的总量、使用量、剩余量, 以及文件系统的格式与相关信息等;

inode table: superblock之后就是inode table, 存储了全部inode.

data block: inode table之后就是data block. 文件的内容保存在这个区域. 磁盘上所有块的大小都一样.

inode: 记录文件的属性, 同时记录此文件的数据所在的block号码. 每个inode对应一个文件/目录的结构, 这个结构它包含了一个文件的长度、创建及修改时间、权限、所属关系、磁盘中的位置等信息.

block: 实际记录文件的内容. 一个较大的文件很容易分布上千个独产的磁盘块中, 而且, 一般都不连续, 太散会导致读写性能急剧下降.

好, 我猜你和我一样是右脑思维, 上图就好:

AAffA0nNPuCLAAAAAElFTkSuQmCC

可以看出来, 这是多层索引结构的文件系统. 用b+树是最佳解决方案, 比如btrfs. inode table指向inode, inode指向一个或者多个block, 注意, 图中还是直接指向, 后面还会讲述多层指向. 最怕的就是inode指向的block太散. 一个比较好的解决办法就是在文件末尾不断添加数据, 而不是新建文件.

新建文件和inode

新建一个文件和文件夹, 用stat指令查看文件信息.

touch hello

stat hello

mkdir hellodir

stat hellodir

AAffA0nNPuCLAAAAAElFTkSuQmCC

可以看到一些信息. 例如一个目录初始大小就是4KB, 8个block, 一个扇区就是512B, 一个io block是4KB, 对应第一幅图的General Block Device Layer层. 这些其实不看也知道, 前提是这是常规的fs.

文件创建过程

创建成功一个文件有4步:

存储属性: 也就是文件属性的存储, 内核先找到一块空的inode. 例如, 之前的1049143. 内核把文件的信息记录其中. 如文件的大小、文件所有者、和创建时间等, 用stat指令都可以看到.

存储数据: 即文件内容的存储, 比方建立一个1B的文件, 那一个block, 8个扇区, 内核把数据放到一个空闲逻辑块中也就是空闲block中. 很明显, 碎片化的问题已经呈现在这里了. 1B它也要用4K对吧.

记录分配情况: 假如数据保存到了3个block中, 位置要记录到inode的磁盘序号列表中. 这3个编号分别放在最开始的3个位置. 然后读的时候会一次性读, 可以看我的第二张图. 当然了fat就没有inode, 它在一个块中放了下一个块的位置, 形成链, u盘就是这种fs.

添加文件名到目录: 文件名和inode之间的对应关系将文件名和文件以及文件的内容属性连接起来, 找到文件名就找到文件的inode,通过inode就能找到文件的属性和内容. 换句话说, 就是机器看的和人看的做衔接, 例如网址和ip. 当然, 如果你看inode就能区分文件, 第四步可以不要(手动滑稽).

目录的话, 就是多了点文件(指向自己), 点点文件(指向上级目录). 然后添加自己的inode到上级目录. 看图就秒懂了.

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCC

inode解析

用df指令可以看inode的总数和使用量.

df -i

dumpe2fs打开指定磁盘可以看inode的大小, 这里是256.

AAffA0nNPuCLAAAAAElFTkSuQmCC

inode如何记录文件并且最大是多少呢? inode记录block号码的区域定义为12个直接, 一个间接, 一个双间接与一个三间接记录区. 一个inode是4B, 这样用4K的block可以有1K的inode.

直接: 12 * 4K

间接: (4K / 4) * 4K

双间接: (4K / 4) * (4K / 4) * 4K

三间接: (4K / 4) * (4K / 4) * (4K / 4) * 4K

所以的话, 4T, are you OK? 算归算, fs在不断发展, 这是过时的大小了. ext4的话单个文件可以到达16TB, fs可达1EB. 但是注意, ext4的作者都说了, ext4只是过渡, btrfs会更棒, 那事实上, cent os用的xfs也很很棒.

打开文件

创建之后当然要打开了, 打开文件也是有一系列过程的. 先来看看两个指令:

sysctl -a | grep fs.file-max

ulimit -n

AAffA0nNPuCLAAAAAElFTkSuQmCC

第一个指令查看os最大打开数, 这是系统级限制.

第二个指令查看单进程最大打开数, 这是用户级限制.

进程描述符(task_struct):

为了管理进程, 操作系统要对每个进程所做的事情进行清楚地描述, 为此, 操作系统使用数据结构来代表处理不同的实体, 这个数据结构就是通常所说的进程描述符或进程控制块(PCB). 通俗来讲就是操作系统中描述进程的结构体叫做PCB.

Linux内核通过一个被称为进程描述符的task_struct结构体来管理进程, 这个结构体包含了一个进程所需的所有信息. 它定义在include/linux/sched.h文件中. 这不是这次的重点, 但是这个task_struct结构体确实很重要, 也很复杂.

每个进程都会被分配一个task_struct结构, 它包含了这个进程的所有信息, 在任何时候操作系统都能跟踪这个结构的信息.

文件描述符表(file_struct): 该表记录进程打开的文件. 它的表项里面有一个指针, 指向存放在内核空间的文件表中的一个表项. 它向用户提供一个简单的文件描述符(fd), 使得用户可以通过方便地访问一个文件. 例如, 当进程使用open打开一个文件时, 内核就会在这个表中添加一个表项. 如果对同一个文件打开多次, 那么将有多个表项. 使用dup时, 也会增加一个表项.

文件表: 文件表保存了进程对文件读写的偏移量. 该表还保存了进程对文件的存取权限等等. 比如, 进程以O_RDONLY方式打开文件, 这将记录到对应的文件表表项中. 然后每个表有一个指向inode table中inode的指针. 结合之前的图片看, 所有结构就联系起来了, 所以inode是核心点.

上图上图:

AAffA0nNPuCLAAAAAElFTkSuQmCC

在进程A中, 文件描述符1和2都指向了同一个打开的文件表A. 这可能是通过调用dup()、dup2()、fcntl()或者对同一个文件多次调用了open()函数而形成的.

进程A的文件描述符0和进程B的文件描述符2都指向了同一个打开的文件表A. 这种情形可能是在调用fork()后出现的(即, 进程A、B是父子进程关系), 或者当某进程通过UNIX域套接字将一个打开的文件描述符传递给另一个进程时, 也会发生. 再者是不同的进程独自去调用open函数打开了同一个文件, 此时进程内部的描述符正好分配到与其他进程打开该文件的描述符一样.

此外, 进程A的描述符0和进程B的描述符255分别指向不同的打开文件表, 但这些文件表均指向inode table的相同条目(假设), 也就是指向同一个文件. 发生这种情况是因为每个进程各自对同一个文件发起了open()调用。同一个进程两次打开同一个文件, 也会发生类似情况.

为什么要说这些情况呢? 因为如果没有理解清楚这些, 在做多进程多线程read和write的时候很有可能会导致读取和写入混乱.

参考

看了非常多很棒的文章, 这里也分享给大家.

最后

这次从结构上逐步往内解剖文件系统, inode是核心点. 当然还有两篇甚至更多的后续文章, 最后会写个简单的用户态文件系统, 喜欢记得点个赞或者关注我哦~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/528883.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

gps卫星位置计算程序matlab_科研项目 | BD/ GPS卫星导航仿真测试系统研究

一、项目背景在移动互联和互联网的时代,卫星导航定位已经成为生活中不可或缺的部分。目前,我国的交通、银行、电力、采矿、测绘等部门以及大众化市场都需要大量的定位、授时服务。许多企业也形成了覆盖卫星导航相关材料及元器件、卫星导航芯片、卫星导航…

linux docker权限,linux - 如何解决ubuntu中的docker权限问题? - Ubuntu问答

问题描述我已经按照here的说明安装了docker。我使用Ubuntu Trusty 14.04 (LTS) (64-bit)。安装过程中的一切都很好。另外,命令$ sudo docker run -i -t ubuntu /bin/bash可以很好地完成(在打开的控制台中键入”exit”之后。但是当我尝试执行其他操作时,我…

python虚拟人脸生成_GitHub - 597111463/seeprettyface-generator-yellow: 这是一个用StyleGAN训练出的黄种人人脸生成器...

黄种人人脸生成器注明:之前做的一些有意思的人脸生成器,现在全部开源分享出来。它的主要作用是可生成制作各类型的人脸素材,供我们任意使用且无须担心人脸版权的问题。在定制人脸上,开源的全系列生成器包括:黄种人脸生…

Linux输入密码接口,Linux下搭建接口自动化测试平台

前言我们今天来学习一下在Linux下如何搭建基于HttpRunner开发的接口自动化测试平台吧!需要在Linux上提前准备的环境(下面是本人搭建时的环境):1,Python 3.6.8 (可参考随笔:Linux学习6-安装Python3.6)2,MySQL 5.7(可参考…

python构建字典实现英文大写字母与ascii编码的转换_Python:将复杂的字符串字典从Unicode转换为ASCII...

作为从JSON API调用解析的多级字典,我有很多输入.字符串都是unicode,这意味着有很多ustuff like this.我正在使用jq来处理结果,需要将这些结果转换为ASCII.我知道我可以编写一个函数来像这样转换它:def convert(input):if isinstance(input, dict):ret {}for stuff in input:r…

linux下查看windows文件夹大小,如何从Windows命令行检查文件夹的大小?

我意识到这个问题要求使用进行文件大小分析CMD line。但是,如果您愿意使用它,PowerQuery (Excel add-in, versions 2010)则可以创建一些非常引人注目的文件大小分析。下面的脚本可以粘贴到空白查询中;您唯一需要做的就是添加一个名为“ param…

python多进程传递参数_急急急, Python 多进程,如何传递 epoll?

102019-06-16 15:39:41 08:00NoAnyLove 好的好的,我查了下,说 IPC 或向 worker 参数传递的东西必须要能 pickle,不然就报错,那就是 select.epoll 是不支持的。error:TypeError: cant pickle select.epoll objects。代码…

linux查看一小时之内的日志,linux – 在[timespan]内(例如最后一小时)查找日志文件中的条目...

我的服务器CPU使用率不高,我可以看到Apache正在使用太多的内存。我有一种感觉,我正在用一个IP进行DOS.-也许你可以帮我找到他?我已经使用以下行找到10个最“活跃”的IP:cat access.log | awk {print $1} |sort |uniq -c |sort -n …

图像语义分割_图像语义分割(9)-DeepLabV3: 再次思考用于图像语义分割的空洞卷积...

论文地址 :Rethinking Atrous Convolution for Semantic Image Segmentation论文代码:Github链接1. 摘要文章主要的工作:使用空洞卷积来调整滤波器的感受野并控制特征图分辨率使用不同空洞率的空洞卷积的串联或者并行操作来分割不同尺度的目标…

linux系统列表,Linux常用系统调用列表-20210415054405.docx-原创力文档

LinuxLinux常用系统调用列表作者:雷震 2002年3月本文列出了大部分常见的Linux系统调用,并附有简要中文说明。以下是Linux系统调用的一个列表,包含了大部分常用系统调用和由系统调用派 生出的的函数。按照惯例,这个列表以man pages…

sql replace 双引号变单引号_sql-汇总、排序以及分析思路

一、汇总函数注:汇总函数,如果输入是列名,计算会把null 排除在外,count(*)对所有的行进行计数二、如何用sql解决业务问题注1:空值(null)的排序,排序是最小的,例如select * from tea order by tea_name注2&a…

linux subversion 根目录检出,经验总结:详解Linux下Subversion的安装配置记录 下

上节介绍额Linux下Subversion的安装问题,本节介绍Linux下Subversion配置问题,你可以和Windows下Subversion的安装配置做一个对比,你就会发现在这两种操作系统中Subversion的不同运行机制。第二章配置本系统采用为每个项目单独建一版本库的策略…

python用户名密码登录退出_用户登录登出

一、功能需求分析1.登录功能分析1.1登录流程1.2功能(一个请求为一个功能)~登录页面~登录功能~登出功能二、登录页面1.接口设计1.1.接口说明类目                  说明请求方式                GETurl定义…

openwrt是嵌入式linux,非常方便的OpenWrt的嵌入式Linux开发环境

今天听中央经济广播电台说,今年有559万大学毕业生,大学生的就业形式严峻.我想那些精通Linux开发的毕业大学生们,估计一点也不用担心,因为他们已经不再是一颗大白菜了.最近在帮一个朋友把OpenWrt移植到一块单板上,有一些心得,分享给大家.OpenWrt是一个很好的学习Linux的平台,而且…

linux添加有效群组,Linux中的有效群组和初始群组

在Linux中,每个账号都可以加入多个群组,那用户登录后默认的用的是哪个群组呢?关于这个问题就要说说有效群组和初始群组了。在用户账号信息文件/etc/passwd中,那个由冒号分割的7个栏目中,第四个栏目是群组ID(GID)&#…

php多个表中查找数据_HeidiSQL 免费的可视化数据库管理工具

HeidiSQL是一款免费的软件,并且易于学习和使用。HeidiSQL让你从数据库内可视化的读写数据、结构体。它支持MariaDB、MySQL、Microsoft SQL、PostgreSQL等数据库。功能免费且开源内置中文在同个窗口连接多个服务支持以命令行形式连接服务连接支持SSH、SSL创建修改表、…

嵌入式linux启动根文件系统,嵌入式Linux根文件系统制作和挂载

嵌入式Linux系统由三部分组成: uboot、kernel、根文件系统, 还是这张老图这里的根文件系统可以说是包含两个部分: 一个是根,一个是文件系统那么什么是根呢?哈哈 其实根表示的就是第一个的意思下面贴张图看看整个根文件…

sqlite 查询 支持多用户同时_SQLite支持多进程同时操作数据库文件吗?

多个进程可以同时打开同一个数据库。多个进程可以同时执行SELECT。但是,只有一个进程可以随时对数据库进行更改。SQLite使用读/写锁来控制对数据库的访问。(在Win95 / 98 / ME下,缺少对读写锁的支持,而是使用概率模拟。)但请注意:…

python 字符串处理 字典_python 字符串和字典

一、字符串操作name "my name is \t {name} and i am {year} years old"1.首字母大写print(name.capitalize())2.统计字符串中相同的字符print(name.count("n"))3.格式化字符串print(name.center(50,"-"))#打印50个-,把name的值放中…

查询linux上调度命令,浅析Linux中crontab任务调度

一.创建调度任务指令crontab -e 进入当前用户编辑界面crontab -u 用户名 -e 进入指定用户编辑界面进入crontab任务编辑界面任务编写格式#每分钟执行查看一次/ect目录,把目录内容写进/tml/a.txt下*/ 1 * * * * ll /etc >> /tmp/a.text#crontab对象 指令#多个任务同时执行#…