Linux篇:文件系统

news2024/11/25 7:05:03

一、共识原理:
文件=文件内容+文件属性
磁盘上存储文件=存文件的内容(数据块)+存文件的属性(inode)
Linux的文件在磁盘中存储是将属性和内容分开存储的。

二、硬件简述:
1. 认识硬件
磁盘:唯一的一个机械设备,也是一个外设。磁头一面一个,磁头和盘面不接触。是永久性存储介质,高温会退磁。
内存:掉电易失性存储介质。
磁带:类似于磁盘。

2、磁盘的存储构成
磁盘被访问的最基本单元是扇区(512字节/4KB),我们可以把磁盘看作有无数个扇区构成的存储介质。
要把数据存到磁盘,第一个解决的问题是定位一个扇区,哪一面定位用哪个磁头,哪一个磁道,哪一个扇区。
磁头左右摆动,其实质是定位磁道和柱面的过程(运动越少,效率越高;运动越多,效率越低)。
在软件设计上,设计者一定要有意识的将相关数据放在一起。
磁带延展开,逻辑上是线性的,所以磁盘在逻辑上也是线性的。基于扇区的数组,任意一个扇区都有下标。

3、回归到硬件:不仅仅有CPU有寄存器,其他设备外设也有,磁盘也有。
控制寄存器(rw):控制IO方向。
数据寄存器:存储数据。
地址寄存器:逻辑地址(LBA)。
状态寄存器:表示结果。

三、对硬件进行抽象理解(文件系统ext2):

1、分治: 分区->块组->文件系统。

Data blocks:存文件内容的区域,以块的形式呈现,常见的文件系统块大小是4KB(一般而言,每个块只有自己的数据)。

inode Table:很多inode。
inode:inode结构体,包含单个文件的所有属性(inode number,文件类型,权限,引用计数,拥有者,所属组,ACM时间,int blocks[NUM]等),大小是128字节(一般而言,一个文件,一个inode)(文件文件名不在inode保存)。
注:
①在linux中文件的属性中,不包含文件的名称,只知道文件的编号。查找一个文件仅需找到它的inode编号,从而在它的inode表中找到inode,从而找到其blocks数组,根据数组中记载的块号按顺序读出文件内容。
②block数组规定:分为直接索引和简介间接索引。
直接索引:存储文件内容。
间接索引:不存储文件内容,而是继续存储我们的文件版号,从而创建更大的文件。

Block bitmap比特位的位置和块号映射起来,比特位的内容表示该块是否被使用。 
inode bitmap:比特位的位置和inode的编号映射起来,比特位的内容表示inode是否有效。
问:上一个文件的时候用不用把块(文件内容)清空呢?
答:不用。根据文件inode编号,找到inode bitmap(发现位图有效),转而去找inode table,读取其属性获得对应的inode和数据块地址关系,读取所有块号,在bitmap和block map里所有的块号全部清零,其次,根据inode编号找到其bitmap由1置为0。

Group Descriptor Table(不会在每个组都存在):描述整个分组基本的使用情况:一共有多少个组,每个组的大小,每个组的inode数量,每个组的block数量,每个组的起始inode,文件系统的类型与名称等。

Super Block:文件系统的信息:里面包含的是整个分区的基本使用情况。

格式化:每一个分区在被使用前,都必须提前先将部分文件系统的属性信息提前设置进对应的分区中,方便我们后续使用这个分区或者分组。

2、文件理解:
①新建一个文件,系统要做什么?
通过新建路径确定分区,在该分区内分配inode——查询Group Descriptor Table是否还有未使用的inode,然后扫描inode bitmap位图结构并读取,选择最近的未使用的编号,将该比特位由0置1。未来可通过inode编号确定分区。在inode Table内找到inode,将文件属性填入。在Block bitmap确认写入数据量的大小,遍历未使用的块,将对应的块号填充到inode属性中特定的下标里,然后直接跳转到对应的块中,把内容填充进去。
②删除一个文件,系统要做什么?
根据文件所处目录,确定文件所处分区,根据inode范围确定分组,用自己inode编号减去起始inode编号,进而可以在inode bitmap进行索引,根据inode编号在位图中对应的比特位由1置0,根据inode将Block Bitmap对应比特位由1置0。(删除=允许被覆盖)。
③查找一个文件,系统要做什么?同理。
④修改一个文件,系统要做什么?同理。

3、如何理解目录
①Linux系统中,一个文件,一个inode,每一个inode都有自己的inode编号(inode的设置,是以分区为单位的,不能跨分区)
inode表示文件的所有属性,但是文件名并不属于inode内的属性!
②问:可是我怎么知道一个文件的inode编号?使用者从来没关心过inode,用的是文件名。
答:通过目录查找。
③目录也是文件,也有自己的inode,也有自己的内容和属性。目录数据块中存储文件的文件名和对应文件inode的映射关系。
④同一个目录下不能有同名文件,因为key值不能相同。文件名冲突系统就无法找到指定文件了。
⑤目录下,没有w,我们无法创建文件。即便创建了文件,文件名与inode的映射关系也无法写到目录文件的数据块里。
⑥目录下,没有r,我们无法查看文件。无法读取目录所对应数据块的文件名与inode的映射关系无法得到。
⑦目录下,没有x,我们就无法进入这个目录。cd目录名本质上是找到目录的inode,但没有x,无法进入目录,无法更新当前目录环境变量。
⑧问:可是目录是文件,也有inode的编号。怎么找?
答:查任何一个目录使,都要从当前目录开始向上递归找到根目录(此文件文件名确定/),找到该数据块,里面的所有文件子目录数据都可以找到。(绝对路径)
⑨Linux系统中,会把用户最常访问的若干目录路径信息通过dentry缓存。

四、软硬链接:

软链接是一个独立的文件,具有独立的inode
硬链接不是一个独立的文件,因为它没有独立的inode。

1、如何理解硬链接?
所谓建立硬链接,本质其实就是在特定目录的数据块中新增文件名和指向的文件的inode编号的映射关系(类似于取别名)。
任意一个文件,无论是目录,还是普通文件,都有inode。
每一个inode内部,都有一个叫做引用计数的计数器(有多少个文件名指向该文件)(默认引用计数为1,自己指向自己)。
目录里保存的是文件名:inode编号的映射关系(默认引用计数为2,有自己目录的文件名和inode映射关系)(目录内部的.文件是该目录的一个硬链接)。

2、如何理解软链接?
软链接是一个独立的文件,有独立的inode,也有独立的数据块,他的数据块里面保存的是指向文件的路径(类似于快捷方式)。

3、为什么要用软链接?
任意路径软件在系统中能找到的/usr/bin目录下建立软连接,就能不带路径执行。

4、为什么要用硬链接?
通常用来进行路径定位,采用硬链接,可以进行目录间切换。硬链接能够维持Linux整体的目录结构。
注:Linux不允许用户对目录建立硬链接,因为会引发环路问题。(而系统可以,比如.和..)。

五、内存管理简述

1、内存的本质是对数据的临时存取,所以我们在系统层面上把内存看作一个大型的缓冲区。内存中的大部分数据未来都会加载到磁盘里或者释放。物理内存以页框为单位和磁盘以页帧为单位进行数据交互(4KB)。

2、问:为什么要以4KB的方式进行拷贝?
答:
①减少IO的次数/减少访问外设的次数---硬件。
②基于局部性原理的预加载机制---软件。

3、操作系统如何管理内存?
操作系统提供了虚拟地址空间的概念,用户在应用层只能看见虚拟地址,但操作系统也能看到内存的物理地址。操作系统管理内存时,先描述,再组织——用struct page结构体描述page必要的属性信息,存储到struct page mem_array数组中(其中数组的下标称为页号),对内存的管理变成了对数组的管理!
用户要访问一个内存时,只需要先直接找到这个4KB对应的page,就能在系统中找到对应的物理页框。所有申请内存的动作都是在访问内存page数组。
申请内存的本质是检测数组中结构体里flag标志位是否被使用,若未使用则将page的比特位置1即可。

4、伙伴系统算法,slab分派器(了解即可)。

5、文件页缓冲:Linux中我们的每个进程打开的每一个文件都要有自己的inode属性和自己的文件页缓冲区。数据通过基数树/基树(字典树)写入到文件页缓冲区。文件的内容是有偏移量的!可以通过文件内容偏移量按照比特位构成字典序,在字典树中找到相应的文件偏移量与内存中配置对应的映射关系。从而让文件有序地进行刷新。

6、IO子系统:操作系统层面上会提供一个公共的队列IO request queue,所有的上层进程最终将数据通过文件写到内存中,文件中的配置构建成struct request结构体封装到队列里。操作系统所谓的刷新就是将队列里的数据依次提交给磁盘。同时也可以通过IO排序,IO合并优化该过程。

六、动静态库 

1. 回顾:站在库的制作者角度。
libXXX.a---静态链接
libYYY.so---动态链接
把我们提供的方法给别人用,可以把源文件直接给他,也可以把我们的源文代码想办法打包成库(库+.h)
静态库原理:将.c文件编译成.o文件,将.o文件打包成.a文件,将main.c文件编译为.o文件,两者一结合为最后的可执行程序。

//mymath.h

#pragma once

#include <stdio.h>

extern int myerrno;

int add(int x, int y);
int sub(int x, int y);
int mul(int x, int y);
int div(int x, int y);
//mymath.c
#include "mymath.h"

int myerrno = 0;

int add(int x, int y)
{
        return x + y;
}

int sub(int x, int y)
{
        return x - y;
}

int mul(int x, int y)
{
        return x* y;
}

int div(int x, int y)
{
        if(y == 0)
        {
                myerrno = 1;
                return -1;
        }
        return x / y;
}
//Makefile

lib=libmymath.a

$(lib):mymath.o
        ar -rc $@ $^  //$@ $^表示这些文件的起始和尾
mymath.o:mymath.c
        gcc -c $^  //$^:形成同名的.o文件

.PHONY:clean
clean:
        rm -rf *.o *.a lib

.PHONY:output
output:
        mkdir -p lib/include
        mkdir -p lib/mymathlib
        cp *.h lib/include
        cp *.a lib/mymathlib
[root@hecs-210801 lesson27]# ll
total 12
-rw-r--r-- 1 root root 228 Nov 26 10:19 Makefile
-rw-r--r-- 1 root root 251 Nov 26 10:10 mymath.c
-rw-r--r-- 1 root root 148 Nov 26 10:09 mymath.h
[root@hecs-210801 lesson27]# make
gcc -c mymath.c
ar -rc libmymath.a mymath.o
[root@hecs-210801 lesson27]# make output
mkdir -p lib/include
mkdir -p lib/mymathlib
cp *.h lib/include
cp *.a lib/mymathlib
[root@hecs-210801 lesson27]# ll
total 24
drwxr-xr-x 4 root root 4096 Nov 26 10:27 lib
-rw-r--r-- 1 root root 1880 Nov 26 10:27 libmymath.a
-rw-r--r-- 1 root root  228 Nov 26 10:19 Makefile
-rw-r--r-- 1 root root  251 Nov 26 10:10 mymath.c
-rw-r--r-- 1 root root  148 Nov 26 10:09 mymath.h
-rw-r--r-- 1 root root 1704 Nov 26 10:27 mymath.o
[root@hecs-210801 lesson27]# tree lib
lib
├── include
│?? └── mymath.h
└── mymathlib
    └── libmymath.a

2 directories, 2 files

删除lib的指令:

[root@hecs-210801 lesson27]# rm -rf lib

未来我们要把库给别人时仅需提供lib文件夹即可。

在其他目录下使用该库时所包头文件为:

#include “lib/include/mymath.h”

或者让系统在指定目录下找头文件,库文件:

[root@hecs-210801 lesson27]# gcc main.c -I ./lib/include/ -L ./lib/mymathlib/ -lmymath

2、站在库的使用者角度:
①第三方库往后使用的时候,必定要用gcc -l。
②深刻理解errno的本质。
③gcc链接程序时,默认是动态链接的。如果系统中只提供静态链接,gcc则只能对该库进行静态链接。
④如果系统中需要链接多个库,则gcc可以链接多个库。

3、解决下载不到静态库的方法:
①拷贝到系统默认的库路径/lib64/usr/lib64/(库的安装)。
②在系统默认的库路径/lib64/usr/lib64/建立软链接。

4、解决下载不到动态库的方法:
①拷贝到系统默认的库路径/lib64/usr/lib64/(库的安装)。
②在系统默认的库路径/lib64/usr/lib64/建立软链接。
③将自己的库所在的路径,添加到系统的环境变量LD_LIBRARY_PATH中。
④/etc/ld.so.conf.d建立自己的动态库路径的配置文件,然后重新ldconfig即可。

(实际情况,我们用的库都是别人的,成熟的库都采用直接安装到系统的方式。)

5、使用外部库:ncurses--基于终端的图形界面的库。

6、动态库是怎么被加载的。
①动态库在进程运行的时候,是要被加载的(静态库没有),这就是动态库具有可执行权限的原因。
②常见的动态库,被所有相关的可执行程序动态链接,都要使用动态库/共享库。所以,动态库在系统中加载之后,会被所有进程共享。
③动态库被加载的方式为:建立映射,从此往后我们执行的任何代码都是在我们的进程地址空间中进行执行。
④事实上,系统在运行中,一定会存在多个动态库,先描述再组织由OS管理起来。系统中,所有库的加载情况,OS都非常清楚。

7、程序加载前后地址:
①编译好没有加载前的程序是有地址的,其可执行数据区可以被分成很多段。形成可执行程序的编址已经形成了平坦模式(严格遵照地址空间的方式编码),因为编译器也要考虑操作系统。
注:可执行程序的地址为逻辑地址(磁盘中程序形成时所对应的地址,存偏移量)。
②程序加载后的地址进程:当可执行程序加载到内存的时候,每条指令天然的具有物理地址。
③执行程序形成的时候包含入口地址entry(逻辑地址)。
④CPU读取可执行程序时直接将entry加载到内部寄存器(EIP/PC)中,找到正文代码段从而找到页表,此时页表未建立对应的映射,触发缺页中断,于是程序被加载进来,具有了物理地址,从而页表也能填上对应的虚拟地址和物理地址,从而在物理内存中找到对应的指令代码。CPU内读取到的指令内部可能有数据,可能也有地址(虚拟地址)。(CPU读到指令中的地址全是虚拟地址)

8、动静态库的地址:
①问题:动态库在共享区过大,那具体映射到哪里呢?
动态库被加载到固定地址空间中的位置是不可能的。库只需在虚拟内存中任意位置加载,并让让自己内部函数不要采用绝对编址,只表示每个函数在库中的偏移量即可。
fPIC:产生位置无关码(直接用偏移量进行编址)。
②静态库为什么不谈加载,不谈与位置无关?
因为静态库已经拷贝在可执行程序里了,直接按绝对编址编码。

9、虚拟地址最终是怎么转换到物理地址的?
相关内容将会在后续章节讲解。
 

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

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

相关文章

Vue+ElementUI技巧分享:周数选择器

文章目录 前言一、周数的计算逻辑1.1 周数的定义1.2 年初周数的确定1.3 周数的计算方法 二、代码实现2.1 计算周数2.2 获取周的日期范围2.3 根据周数获取日期范围2.4 控件引用2.4.1 控件引用代码分析2.4.2 初始化变量代码分析 2.5 周数选择器完整代码 总结 前言 Vue.js和Eleme…

文心一言 VS 讯飞星火 VS chatgpt (143)-- 算法导论12.1 3题

三、用go语言&#xff0c;设计一个执行中序遍历的非递归算法。&#xff08;提示:一种容易的方法是使用栈作为辅助数据结构;另一种较复杂但比较简洁的做法是不使用栈&#xff0c;但要假设能测试两个指针是否相等。&#xff09; 文心一言&#xff0c;代码正常运行&#xff1a; …

Linux 面试题(一)

目录 1、绝对路径用什么符号表示&#xff1f;当前目录、上层目录用什么表示&#xff1f;主目录用什么表示? 切换目录用什么命令&#xff1f; 2、怎么查看当前进程&#xff1f;怎么执行退出&#xff1f;怎么查看当前路径&#xff1f; 3、怎么清屏&#xff1f;怎么退出当前命…

4G模块(EC600N)通过MQTT连接华为云

目录 一、前言 二、EC600N模块使用 1&#xff0e;透传模式 2&#xff0e;非透传模式 3、华为云的MQTT使用教程&#xff1a; 三、具体连接步骤 1、初始化检测 2、打开MQTT客户端网络 3、创建产品 4、创建模型 5、注册设备 6、连接客户端到MQTT服务器 7、发布主题消…

【数据分享】我国12.5米分辨率的坡向数据(免费获取)

地形数据&#xff0c;也叫DEM数据&#xff0c;是我们在各项研究中最常使用的数据之一。之前我们分享过源于NASA地球科学数据网站发布的12.5米分辨率DEM地形数据&#xff01;基于该数据我们处理得到12.5米分辨率的坡度数据、12.5米分辨率的山体阴影数据&#xff08;均可查看之前…

Python 安装mysqlclient 错误 无法打开包括文件: “mysql.h”: 解决方法

解决方案&#xff1a;python最新3.12.0不支持mysqlclient 请下载 python3.9.9 版本 高速下载地址CNPM Binaries Mirror 官方下载地址Welcome to Python.org 下载完成后将python添加到环境变量 pycharm 虚拟环境下的python版本切换到你刚才下载的3.9.9的python版本 Avai…

C语言标准

1、概述 C语言标准是由ANSI&#xff08;美国国家标准协会&#xff09;和ISO&#xff08;国际标准化组织&#xff09;共同制定的一种语言规范。标准经历过如下更新&#xff1a; C89/C90标准C99标准C11标准C17标准 2、C89/C90标准 (1)这是1989年正式发布的C语言标准&#xff0…

使用项目管理工具进行新媒体运营管理的策略与方法

使用Zoho Projects项目管理工具&#xff0c;新媒体运营可轻松驾驭从策划选题、撰写到排期发布的全流程。运用项目管理工具对新媒体运营进行精细化管理&#xff0c;助力团队更高效地规划、执行和追踪各项任务与活动。 以下是运用项目管理工具管理新媒体运营的妙招&#xff1a; 1…

Java进阶(第二期):package 包 抽象类和抽象方法 接口的实现 多态的实现 综合继承、接口、多态的使用。

2023年11月26日20:11:11 文章目录 Java进阶&#xff08;第二期&#xff09;一、package包的概念二、抽象类和抽象方法(abstract)2.1 使用2.1 抽象类注意事项 三、接口3.1 接口的定义格式3.2 接口成员特点3.3 类和接口的关系3.4 接口和抽象类的对比 四、多态4.1 多态的前提条件4…

2009年iMac装64位windows7及win10

2009年iMac装64位windows7及win10 Boot Camp没有“创建 Windows7 或更高版本的安装磁盘”选项 安装完Mac OS系统后&#xff0c;要制作Windows7安装U盘时才发现&#xff0c;Boot Camp没有“创建 Windows7 或更高版本的安装磁盘”选项&#xff0c;搜索到文章&#xff1a;修改Boo…

Mac 最佳使用指南

如何在macOS系统安装根证书mac Terminal config proxy 【mac 终端配置代理】iPhone 安装 iOS 17公测版&#xff08;Public Beta)macOS 最佳命令行客户端&#xff1a;iTermMac 配置与 Linux 互信Mac mini 外接移动硬盘无法写入或者无法显示的解决方法如何在 macOS 美化 iterm2 &…

更改MacBook壁纸,有时可以带来不一样的感觉,特别是动态壁纸

在我看来&#xff0c;买一台新的MacBook最棒的部分就是挑选一张完美的桌面壁纸&#xff0c;为我的新工作伙伴定下基调。有时&#xff0c;在真正更换壁纸之前&#xff0c;我会花一整天的时间&#xff0c;仔细决定我的新笔记本电脑到底是什么样子&#xff0c;而且由于Macbook如此…

《数据结构、算法与应用C++语言描述》-二叉树与其他树-二叉树的C++实现-设置信号放大器与并查集问题

二叉树和其他树 可编译运行程序见&#xff1a;Github::Jasmine-up/Data-Structures-Algorithms-and-Applications/_23BinaryTree 定义 树 定义 11-1 一棵树 t是一个非空的有限元素的集合&#xff0c;其中一个元素为根&#xff08;root&#xff09;&#xff0c;其余的元素&a…

Redis面试题:Redis的数据过期策略有哪些?

目录 面试官&#xff1a;Redis的数据过期策略有哪些 ? 惰性删除 定期删除 面试官&#xff1a;Redis的数据过期策略有哪些 ? 候选人&#xff1a; 嗯~&#xff0c;在redis中提供了两种数据过期删除策略 第一种是惰性删除&#xff0c;在设置该key过期时间后&#xff0c;我们…

6.4 Windows驱动开发:内核枚举DpcTimer定时器

在操作系统内核中&#xff0c;DPC&#xff08;Deferred Procedure Call&#xff09;是一种延迟执行的过程调用机制&#xff0c;用于在中断服务例程&#xff08;ISR&#xff09;的上下文之外执行一些工作。DPC定时器是基于DPC机制的一种定时执行任务的方式。 DPC定时器的主要特…

jsp生成验证码的代码

效果图&#xff1a; loginProcess.jsp <% page language"java" contentType"text/html; charsetUTF-8"pageEncoding"UTF-8"%><% String captcharequest.getParameter("captcha");%><% String captcha_session(String)s…

记一次Kotlin Visibility Modifiers引发的问题

概述 测试环境爆出ERROR告警日志java.lang.IllegalStateException: Didnt find report for specified language&#xff0c;登录测试环境ELK查到如下具体的报错堆栈日志&#xff1a; java.lang.IllegalStateException: Didnt find report for specified language at com.aba.…

基于51单片机红外遥控定时开关智能家电插座设计

**单片机设计介绍&#xff0c; 基于51单片机超声波测距汽车避障系统 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 设计一个基于51单片机红外遥控定时开关智能家电插座是一个涉及多个方面的复杂项目。以下是对该设计的基本介绍&…

Stm32CubeMx生成代码提示缺少“core_cm3.h“

Stm32CubeMx生成代码提示缺少"core_cm3.h" 1.原因分析 1.1问题根源 在我们使用本地解压的方法去安装固件包,但是找错了要下载的固件包&#x1f60a;.在你点击进入下载页面之后,能看到一共有两个下载链接,其中上面的是补丁包,而第二个才是我们应该要下载的固件包 当…