Linux篇:文件系统

一、共识原理:
文件=文件内容+文件属性
磁盘上存储文件=存文件的内容(数据块)+存文件的属性(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、虚拟地址最终是怎么转换到物理地址的?
相关内容将会在后续章节讲解。
 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

4.一维数组——用数组处理求Fibonacci数列前20项

文章目录 前言一、题目描述 二、题目分析 三、解题 程序运行代码 四、结果显示 前言 本系列为一维数组编程题&#xff0c;点滴成长&#xff0c;一起逆袭。 一、题目描述 用数组处理求Fibonacci数列前20项 二、题目分析 前两项&#xff1a;f[20]{1,1} 后18项&#xff1a;for(…

vue3+tsx的使用

<template><div><xiaoman on-click"getItem" name"似懂非懂"></xiaoman></div> </template><script setup langts>import xiaoman from "./App"const getItem(item:any)>{console.log(item,it…

王者小游戏作业

一、创建好文件、包、类、插入图片文件夹 二、beast包 1、Bear类 package beast; import sxt.GameFrame; public class Bear extends Beast {public Bear(int x, int y, GameFrame gameFrame) {super(x, y, gameFrame);setImg("C:\\Users\\陆先生\\Desktop\\王者荣耀图片…

C++学习之路(四)C++ 实现简单的待办事项列表命令行应用 - 示例代码拆分讲解

本期示例介绍: 本期示例《待办事项列表应用》展示了一个简单的任务管理系统&#xff0c;用户可以通过命令行界面执行添加任务、删除任务和显示任务列表等操作。 功能描述&#xff1a; 添加任务功能&#xff1a; 用户可以输入任务描述&#xff0c;将新的任务添加到任务列表中。…

设计模式—依赖倒置原则(DIP)

1.概念 依赖倒置原则&#xff08;Dependence Inversion Principle&#xff09;是程序要依赖于抽象接口&#xff0c;不要依赖于具体实现。简单的说就是要求对抽象进行编程&#xff0c;不要对实现进行编程&#xff0c;这样就降低了客户与实现模块间的耦合。 通俗的讲&#xff1…

【教学类-06-13】20231126 (55格版)趣味题(一)1-9加法题(10倍)(整十相加)

作品展示 背景需求&#xff1a; 1、会做加法题的孩子5分钟内完成题目&#xff0c;太快了&#xff0c;所以为了拉平差异&#xff0c;需要给这些会做另外的题目&#xff0c;比如提供一些他们没有做过的“趣味题形”。 2、好多次&#xff0c;听见大班孩子在互相“考试”——“老…

04_MySQL备份与恢复

任务背景 一、真实案例 某天&#xff0c;公司领导安排刚入职不久的小冯同学将生产环境中的数据(MySQL数据库)全部导入到测试环境给测试人员使用。当小冯去拿备份数据时发现&#xff0c;备份数据是1个礼拜之前的。原因是之前运维同事通过脚本每天对数据库进行备份&#xff0c;…

2023年程序设计迎新赛(第二届个人程序设计大赛)

7-1 找规律 请从所给的四个选项中&#xff0c;选择最合适的一个填入问号处&#xff0c;使之呈现一定的规律性。 输入格式: 无 输出格式: 大写字母 输入样例: 输出样例: #include<stdio.h> int main(){printf("D");return 0; }7-2 蜡烛燃烧时间 有粗细不同…

【MySQL】JDBC编程

&#x1f451;专栏内容&#xff1a;MySQL⛪个人主页&#xff1a;子夜的星的主页&#x1f495;座右铭&#xff1a;前路未远&#xff0c;步履不停 目录 一、JDBC工作原理二、JDBC 使用1、准备工作2、使用实例3、手动输入 一、JDBC工作原理 JDBC是Java语言中用于与数据库进行交互…

Vscode工具使用指南

通用 快捷键文件 / 编辑查找 / 替换窗口插件主题 连接linux 快捷键 文件 / 编辑 新建文件&#xff1a;CtrlN放大或缩小&#xff1a;Ctrl /-代码行缩进&#xff0c;展开&#xff1a;Ctrl[ 和 Ctrl]在当前行下方插入一行&#xff1a;CtrlEnter在当前行上方插入一行&#xff1a;…

【方块消消乐】方块消除游戏-微信小程序开发流程详解

有做过俄罗斯方块游戏小程序的经验&#xff0c;这次有做了一个消灭方块的游戏&#xff0c;实现过程很顺利&#xff0c;游戏看着和之前做的俄罗斯方块游戏很像&#xff0c;这里调整了玩法&#xff0c;试玩感觉还可以&#xff0c;接下来给大家讲一讲消灭方块游戏开发过程。 俄罗斯…

Unity2D-URP基于ShaderGraph创建带粒子特效的激光光束

文章目录 创建Shader新建Node: UV新建Node: Split......参数说明 基于Shader创建Material创建Line创建粒子系统StartVFX创建粒子材质更改粒子系统的材质设置透明模式设置粒子效果创建一个Beam设置EndVFX效果预览激光光束管理脚本最终预览 创建Shader Create --> Shader Gra…

Redis面试题:Redis的数据淘汰策略有哪些?

目录 面试官&#xff1a;Redis的数据淘汰策略有哪些 ? 面试官&#xff1a;数据库有1000万数据 ,Redis只能缓存20w数据, 如何保证Redis中的数据都是热点数据 ? 面试官&#xff1a;Redis的内存用完了会发生什么&#xff1f; 面试官&#xff1a;Redis的数据淘汰策略有哪些 ? …

掌握文件夹重命名技巧:字母大小写批量转换的实用操作

在这个数字化时代&#xff0c;经常要与各种文件和文件夹打交道。有时候&#xff0c;为了提高工作效率或整理文件&#xff0c;要对文件夹名称进行修改。其中&#xff0c;字母大小写的转换是一个常见的需求。例如&#xff0c;将所有文件夹名称中的大写字母转换为小写字母&#xf…

【Linux系统编程】冯 • 诺依曼体系结构(什么是冯 • 诺依曼体系结构?冯 • 诺依曼体系结构如何应用?)

目录 一、前言 二、什么是冯 • 诺依曼体系结构&#xff1f; &#x1f4a6; 冯 • 诺依曼体系结构的发展推导 &#x1f4a6;冯 • 诺依曼体系结构的5大部件 ⭐输入和输出设备 ⭐存储器 ⭐中央处理器&#xff08;CPU&#xff09; &#x1f4a6;冯 • 诺依曼体系结构的细节…

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

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

Python 测试框架 Pytest 的入门

简介 pytest 是一个功能强大而易于使用的 Python 测试框架。它提供了简单的语法和灵活的功能&#xff0c;用于编写和组织测试代码。 1、简单易用&#xff1a;pytest 的语法简洁明了&#xff0c;使得编写测试用例更加直观和易于理解。它使用 assert 语句来验证预期结果&#x…

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…

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

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

2023-11-26 事业-代号s-跨境物流-记录

摘要: 2023-11-26 事业-代号s-跨境物流-记录 跨境物流: 【结论】 中小卖家&#xff08;最低适合1个人经营的卖家&#xff09;首选以下两种物流&#xff0c;目前已知的是以下两种&#xff0c;后续有新的发现再更新。 1、云途物流&#xff08;YunExpress&#xff09;&#xff…