qemu cxl

1
2
3
4
5
6
7
8
9
./build/aarch64-softmmu/qemu-system-aarch64 -M virt,gic-version=3,cxl=on -m 4g,maxmem=8G,slots=8 -cpu max \
-hda ../vm_disk/ubuntu_cxl.qcow2 \
-cdrom ../ubuntu-20.04.5-desktop-amd64.iso \
-object memory-backend-file,id=cxl-mem1,share=on,mem-path=/tmp/cxltest.raw,size=256M \
-object memory-backend-file,id=cxl-lsa1,share=on,mem-path=/tmp/lsa.raw,size=256M \
-device pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1 \
-device cxl-rp,port=0,bus=cxl.1,id=root_port13,chassis=0,slot=2 \
-device cxl-type3,bus=root_port13,memdev=cxl-mem1,lsa=cxl-lsa1,id=cxl-pmem0 \
-M cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.size=4G

-M

Libnvdimm

image-20221015200747925

image-20221015200623751

image-20221015200854839

1
2
3
4
5
6
7
8
9
10
11
12
13
~/qemu/build/aarch64-softmmu/qemu-system-aarch64 -M virt,gic-version=3,cxl=on -m 4g,maxmem=8G,slots=8 -cpu max \
-bios ~/repo/edk2/Build/ArmVirtQemu-AARCH64/DEBUG_GCC48/FV/QEMU_EFI.fd \
-kernel ~/linux/arch/arm64/boot/Image \
-initrd ./rootfs.cpio.gz \
-monitor telnet:127.0.0.1:4444,server,nowait \
-object memory-backend-file,id=cxl-mem1,share=on,mem-path=/tmp/cxltest.raw,size=256M \
-object memory-backend-file,id=cxl-lsa1,share=on,mem-path=/tmp/lsa.raw,size=256M \
-device pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1 \
-device cxl-rp,port=0,bus=cxl.1,id=root_port13,chassis=0,slot=2 \
-device cxl-type3,bus=root_port13,memdev=cxl-mem1,lsa=cxl-lsa1,id=cxl-pmem0 \
-cxl-fixed-memory-window targets.0=cxl.1,size=4G \
-append "console=ttyAMA0 root=/dev/ram rdinit=/init acpi=on" \
-nographic \

image-20221015202421449

State-of-the-art Shitcode

1
2
3
4
5
6
7
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j16
sudo make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- modules_install
sudo make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- install
sudo update-grub
reboot

CSAPP Linking 笔记

符号和符号表

static属性声明的全局变量/函数都是模块私有的,任意不被static修饰的全局变量/函数都是公共的,可以被其他模块访问

因此,在每个可重定位目标模块中存在三类符号

  • 自己定义的全局符号
  • 由其他模块定义并由该模块引用的全局符号
  • 自己定义的局部符号–static修饰的函数/全局变量

符号解析

编译器解析符号引用的办法是将每个与它输入的可重定位目标文件中的一个确定的符号定义关联起来

如何解析多重定义的全局符号

区别强弱定义: (我的理解) 强定义是全局定义后有初始值,弱定义没有

  1. 不允许有多个同名的强符号
  2. 如果有一个强符号和多个弱符号同名,则选择强符号
  3. 如果多个弱符号同名,则随机选择一个

CSAPP 存储器层次结构 笔记

6.1 存储技术

  • 随机访问存储器 RAM

    • 静态 SRAM

      位存储模式:双稳态存储器单元

      只要有电,就能永远保持值

    • 动态 DRAM

      位存储模式: 电容充电

    • 比较

    • 每位晶体管数相对访问时间持续?敏感相对花费应用
      SRAM611000高速缓冲存储器
      DRAM1101主存/帧缓冲区
    • 非易失性存储器 ROM

      关电后仍然能保持信息

    • 访问主存

      通过数据总线和主存信息交互

  • 磁盘存储

    • 从磁盘读数据的效率是从DRAM读数据的几乎10万倍慢,不过ssd会快的多,不过只是相对于传统磁盘而言

    • 固态磁盘SSD

      • 读SSD比写要快

        • 因为随机写要擦除块,这个动作是毫秒级的
        • 如果试图写一个有数据的块,会先将这块的数据复制到另一个没数据的地方
      • SSD多次重复写后会损坏

6.2局部性

局部性原理

计算机程序倾向于引用邻近与其他最近引用过的数据项的数据项

简单原则

  • 重复引用相同变量的程序有良好的时间局部性
  • 对于步长为k的引用模式的程序,步长越小,空间局部性越好.
  • 对于取指令来说,循环有好的时间和空间局部性.循环体越小,迭代次数越多,局部性越好

6.3 存储器层次结构

  • L0 寄存器 –保存着从高速缓存中取出的字
  • L1 高速缓存 SRAM –缓存着从L2取出的缓存行 – 速度接近寄存器
  • L2 高速缓存 SRAM –缓存着从L3取出的缓存行 – 速度比L1慢
  • L3 高速缓存 SRAM –缓存着从主存高速缓存取出的缓存行 –速度比L2慢
  • L4 主存 DRAM – 保存着从本地磁盘取出的代码块
  • L5 本地耳机存储 本地磁盘 –保存着从远程网络服务器磁盘上读取的文件
  • L6 远程二级存储 [分布式文件系统,Web服务器]

6.4 高速缓存存储器

6.4.1 通用的高速缓存存储器组织结构

存储器地址位数: m

存储器地址数: M=2^m

高速缓存组数 S= 2^s

高速缓存组内缓存行: E

缓存行内数据块 B=2^b

高速缓存大小: C=S*E*B

6.4.2 直接映射高速缓存

特征: 每个组只有一行,因此字选择时简单,但容易发生抖动

流程: 假设执行一条读内存字w的指令

组选择:

  • 从w中抽取s个组标记位,s由高速缓存组数决定
  • 之后查看高速缓存中是否存在该组,如果存在就得到一个缓存命中,不存在就是缓存不命中

字选择:

  • 高速缓存中的偏移位标识了字节在块中的偏移

行替换:

  • 如果缓存不命中,就需要从层次结构的下一层中取出被请求的块,然后将心的块存储在组索引所示的块中

示例:

  • 书P429

冲突不命中:

  • 由直接映射的设计可以看出,如果程序访问大小为2的幂的数组,很可能会发生冲突不命中.
  • 相同组映射的内存块会不断的来回覆盖–抖动

6.4.3 组相联高速缓存

每个组都有 1<E<C/B 个高速缓存行的 的高速缓存通常称为E路组相联高速缓存

如果E=C/B 称为全相联高速缓存

行匹配

  • 检查多个行的标记和有效位,判断是否在缓存中

行替换

  • 如果组中有空行,则换到空行上去
  • 如果没有,则根据替换策略替换–比如LRU

6.4.4 写回

怎么更新层次结构中,低一层的副本

  1. 直写 – write throuth
    • 立即将w的高速缓存块写回到紧接着的第一层
    • 每次写都会引起总线流量
    • 能够使用独立于高速缓存的写缓冲区用来更新内存
    • 读不命中开销小
  2. 写回[ 延迟更新] write back
    • 只有当替换算法要驱逐这个块时,将这个块写到低一层
    • 显著减少总线流量
    • 增加复杂性– 需要维护一个新的位[修改位]
    • 允许更多到内存的贷款用于执行DMA的I/O.

如何处理写不命中

就是说,要写的块拿不到

  1. 写分配 write-allocate
    • 加载相应的低一层的块到高速缓存中,然后更新这个高速缓存块
    • 写回高速缓存通常是写分配的
  2. 非写分配 not-write-allocate
    • 避开高速缓存,直接把这个字写到低一层中
    • 直写高速缓存通常是非写分配的

6.4.7 性能影响

  1. 不命中率
    • 执行期间,内存引用不命中的比率 不命中数量/引用数量
  2. 命中时间
    • 从高速缓存传送一个字到CPU所需的时间
  3. 不命中处罚
    • 不命中所需的额外时间

下列因素提高的影响

  • 高速缓存:命中率提高,命中时间提高
  • 块大小:命中率提高,不命中处罚提高,损害时间局部性比空间局部性更好的程序的命中率
  • 相联度:降低抖动可能,成本提高,增加不命中处罚

越往层次下面走,传送时间增加,减少传送的数量就更为重要.

6.5 编写高速缓存友好的代码

两个原则

  • 让最常见的情况运行的最快
  • 尽量减少,每个循环内部的缓存不命中数量.

CSAPP Optimize 笔记

5.1 编译器优化能力的局限性

  • 编译器只做安全的优化–优化后和未优化的版本有一样的行为

限制

  • 内存别名使用

编译器并不知道指针指向哪里,因此它必须假设指针可能指向同一个位置.

  • 函数调用

大多数编译器不会去判断一个函数是否有副作用,因此它们倾向于将函数的调用保持不变

内联

包含函数调用的代码可以用内联函数替换过程进行优化,就是将函数内部的执行步骤内联到一起

在gcc中,只尝试单文件的内联,不会尝试多文件的内联(比如一组函数在其他文件内的函数中被调用)

5.2 表示程序性能

标准:CPE

每元素的周期数

5.3 消除低效循环

例如 :可以拿出来的拿出来

5.4减少过程调用

例: 如果一个循环中不断从结构体中的列表中获取值,而同时,结构体会不断对列表中值的存在进行判断

则可在保证安全的情况下,直接获取结构体中的列表进行访问.

5.5消除不必要的内存引用

例如

1
2
3
4
5
6
7
8
9
{// for loop
*dest=*dest+1;
}
// 将dest这个不断访问内存的东西挪到寄存器里
val tmp=*dest;
{
tmp=tmp+1;
}
*dest=tmp

5.6 了解现代处理器

  • 延迟界限

    当一系列操作必须按照严格顺序执行时会碰到

    因为下一条指令开始前,这一条必须结束

    代码中的数据相关限制了处理器利用指令级并行的能力时会碰到延迟界限

  • 吞吐量界限

    是处理器功能单元的原始计算能力,是程序性能的终极限制

5.7 循环展开

  • 比如n长的循环,2个一组展开之后,循环长度/2,这种称之为1*2循环展开

对一个n长的循环,进行k级别的展开,就需要将上限设置为n-k+1,这样最大循环索引会小于n

5.8 提高并行性

5.8.1 多个累积变量

例: 见书P370

上面的例子称之为2*2循环展开

5.8.2重新结合变换

该例子为2*1a循环展开

// slow version

acc= (acc * data[i]) * data[i+1]

//fast version

acc = acc * ( data[i] * data[i+1])

slow版里,每次计算都需要等之前的计算结果出来之后才能继续进行

fast版里,data[i]*& data[i+1]不受约束,因此可以被CPU并行优化,故效率高

5.9 一些限制因素

书P378

5.9.1 寄存器溢出

当用到的临时变量过多,使得寄存器不够用的时候,会调用栈来存储这些变量,这会使得程序效率变低.

5.9.2 分支预测和预测错误处罚

预测错误会导致较大的错误处罚,那么有什么办法来保证这个处罚对程序效率影响较小呢

  1. 不过分关心可预测的分支

    例如,大部分结束循环的语句判断都是不结束,预测时一般都按照不结束来判断. 这时候只在最后一次会导致预测错误处罚.

  2. 书写适合使用条件传送实现的代码

    最好使用条件数据传送而非条件控制转移.

    数据传送示例:

    max=a>b?a:b;

    这种形式适合流水线并行操作.

5.10 应用 性能提高技术

  1. 高级设计: 为遇到的问题选择适当的算法和数据结构
  2. 基本编码原则. 避免限制优化的因素
    1. 消除连续的函数调用
      • 在可能时,将计算一道循环外
    2. 消除不必要的内存引用
      • 引入临时变量来保存中间结果,只有在最后的值计算出来时,才将结果存放到数组和全局变量中.
  3. 低级优化. 结构化代码以利用硬件性能
    1. 展开循环,降低开销
    2. 使用多个累计变量和重新结合技术,找到方法提高指令级并行
    3. 用功能性的风格重写条件操作,使编译采用条件数据传送.

CSAPP Machine Level Programming

C 语言 基础属性

数组的指针运算– 数组存储的是它的指针,其指针++ 会跳过存储数据量的位置(如 int a[10],a++ ,arr[a]会+4)

struct的对齐

由于会根据struct中的最大的基本结构类型[int,double,float 之类的,和列表没关系]来进行对齐[例如,struct中存在double就会按照8byte对齐,如果最大只有int,就按照4byte对齐],因此,最好将结构合理组织,

1
2
3
4
5
6
7
8
9
10
struct S4{//char :1 byte, int : 4byte
char c;// 产生3个用于对齐的内存浪费
int i;
char d;// 产生3个用于对齐的浪费
}// waste 3+3 byte
struct S5{
int i;
char c;
char d;//c,d一并存储,产生2个用于对齐的浪费
}

Memory Layout

IMG:

image-20221007163747876

Buffer OverFlow

image-20221007163839893
  • 注: 内存是按照0x7FFFFFFFFFFF 也就是2^47来作为地址的,所以各位置之间可能会有较大的差距[因为暂时,硬件条件并不会使得整块可供分配的内存id映射被用尽]

stack:

  • 8MB
  • 向下拓展[地址高标号低]

Data:

  • 用于存放程序开始时分配的数据
    • 存放全局变量

Heap:

  • 存放通过malloc/相关函数申请的变量,会动态变化
  • 大的数据块会出现在靠近stack的位置,并向下增长,小的数据块会出现在靠近Data的位置,并向上增长

SharedLibraries:

  • 存放库函数代码[一般在磁盘上]
  • 在运行时动态加载到内存中

Unions

BufferOverFlow

代码注入攻击详解

举例: gets 会不断读取字符串,直至收到一个’\0’

1
2
3
4
5
6
void echo()
{
char buf[4];/* Way too small*/
gets(buf);
puts(buf);
}

此时,若输入大于4个字符,echo还是可以接收

查看汇编代码可以看到,调用echo的时候给stackFrame分配了24byte的空间

如果输入大于23个字符,就会报出 segment fault

  • 这时候该函数的返回位置可能被溢出的字符串覆盖,使得函数不会到main这个接口,而是进入一个新的地区
  • 这就是代码注入攻击

小于23就没事,

How to Avoid

  1. 使用安全的替代
    1. fgets-> gets
    2. strncopy-> strcopy
    3. scanf(“%ns”)-> scanf(“%s”)
  2. Randomized stack offsets– 地址空间布局随机化
    1. 使得每次程序运行的时候,它分配到的缓冲区长度都是变化的
  3. None executable code segments
    1. 在可读/可写等内存标识之外增加一个 “execute” 权限
  4. stack canary 栈保护机制
    1. image-20221007201652095
    2. 程序会检测到栈溢出的问题并返回

A Skill to Avoid Randomized stack offset/None executable code segments

  • 但是躲不开canary

Gadget

A Example:image-20221008122557042

p后面的值恰好和mov rax rdi 相等,结尾又是一个c3,因此这一段额外的代码会在p赋值之后执行,并返回.

这样就实现了在代码中插入一定量的自己的小代码,返回后就可以通过获取rsp栈中的代码,来将之前的代码块拼接一起执行.

GDB Trick

disass [FUNC_NAME]

解析对应函数的汇编代码

CPU虚拟化

MAIN TASK: 执行虚拟机程序指令,响应虚拟机内外部事件

面临的挑战

1. 敏感非特权指令

挑战来源: 基于 陷入-模拟 机制的虚拟化架构只能在所有敏感指令都是特权指令的架构中被建立
敏感指令: 操作敏感物理资源的指令,如I/O指令、页表基地址切换指令等
特权指令; 必须运行在最高特权级的指令,在非特权级中执行这些指令将会触发特权级切换。
解决方案:

软件方案: 解释执行【无脑解释执行所有指令,效率较低】,二进制翻译【将敏感指令替换为其他指令,会增加指令数量】,扫描与修补【在执行前,将敏感指令替换为特权指令,代码局部性较差】,半虚拟化【在执行敏感指令的时候通过超调用主动陷入Hypervisor中,避免扫描二进制代码引入的开销,但是打破了虚拟机和Hypervisor之间的界限】
硬件辅助方案: Intel VT-x,AMD SVM, ARM EL2, RISC-V H-Extension
将所有敏感指令转化为特权指令【可能存在兼容性问题】
引入虚拟化模式

2. 上下文切换

类似进程上下文,虚拟机发生退出时需要保持各寄存器的状态
发生虚拟CPU调度时,需要保存当前虚拟CPU的上下文兵加载待调度虚拟CPU上下文

3. 中断处理

模拟方式:为每一个虚拟机维护一个虚拟中断控制器

QEMU/KVM CPU虚拟化实现

21/12/7 设备管理

设备管理

1. 控制器

控制器的任务是在外设与内存之间完成比特流与字节块之间的转换

1.1寄存器

每个控制器有几个寄存器,操作系统可以往里写东西

1.2数据缓冲区

有些控制器上有,用于大数据传输

1.2.1磁盘控制器

将位流组装为字节存入缓冲区中,形成字节为单位的块

2.控制方式

2.1 程序直接控制

cpu控制全过程

效率低下(CPU一直在等)

2.2中断控制

cpu发送指令,去干别的,等io设备准备好,利用中断通知cpu

2.3 DMA方式(适合高速大量的外设)

cpu启动指令->DMA控制器->(data)->启动外设

整个数据的传输都是在DMA控制下进行的

2.4通道控制方式

cpu连接多个通道,通道连接多个控制器,再连接外部设备

imgtest

3.设备I/o子系统

申请设备

将数据写入设备

从设备读取数据

释放设备

分时式共享使用设备

以一次IO为单位分时使用设备

SPOOLING方式使用外设

利用磁盘上的输入输出并模拟高速外设

IO的组成

I.O交通管制程序

调度程序

设备处理程序

基本思想:分层构建,较低层为较高层服务,使较高层独立于硬件,为用户提供统一接口

I/O设计目标

设备独立性–使软硬件相对独立,给上层软件更好的可移植性

设备统一命名-每种设备都是有名称的,如何命名以方便系统管理和用户使用是一个重要的问题

采取预先设计的,统一的逻辑名称

出错处理:数据尽可能在接近硬件层处理,仅当低层无能为力时,才将错误上交

缓冲技术:设法使数据的到达率和离去率匹配,提高系统的吞吐量

设备的分配:共享设备和独占设备的分配问题

文件系统-操作系统

文件系统

文件管理

文件系统的功能

支持文件所占存储介质空间的分配/回收
支持文件相对起始数据的逻辑块定位到外存上的物理块
支持对文件访问的安全检查
支持对文件的读写访问

文件的结构

逻辑结构(文件组织):

用户看到的文件组织形式,和存储:设备无关

有结构的记录式文件:由一个以上的记录构成

无结构的流式文件:文件没有结构,由一串字符流构成

物理结构:

外存上存放形式,和存储设备特性有很大关系

文件存储器物理特性:

磁带

顺序访问设备→要求文件顺序存放于带上。

磁盘

直接(随机)访问设备→文件可顺序、链接式或随机(通过类似页表的索引结构访问)存放于设备上

文件系统重要作用(之一)

在用户逻辑文件和物理文件之间建立映射

文件存取方式

读写文件存储器上的一个物理块的方法

顺序存取:指对文件中的信息按顺序依次读写

随机存取法:

**直接存取法:允许用户随意存取文件中任意一个物理记录**

**按键存取法:根据文件中各记录的某个数据项内容来存取记录的,这种数据项称之为键**

几种常见的物理存储方式

1. 连续存储(顺序结构)

它将逻辑上连续的文件信息依次存放在编号连续的物理块上。

l优点:

存储方式简单。

对文件记录进行批量存取时,其存取效率较高。

支持定长记录的直接存取,可以通过计算获得存储位置。

l缺点:

不支持随机查找。如果要随机地查找或修改单个记录,此时系统需要逐个地查找诸记录,性能较差,尤其是当文件较大时情况将更为严重。

存在外部碎片。

不便于记录的增加或删除操作。

  1. 链接结构

    将逻辑上连续的文件信息存放在不连续的物理块上,每个物理块设有一个指针指向下一个物理块。

    l优点:

    提高了磁盘空间利用率,不存在外部碎片问题。

    有利于文件插入和删除,及其动态扩充。

    l缺点:

    仍然不支持随机查找。

    由于存储空间可能不连续,带来更多的寻道次数和寻道时间。

    需要牺牲一些空间存放链接指针,同时需要维护这些指针,增加了系统开销。

    可靠性问题,如指针出错。

  2. 索引结构
    将逻辑上连续的文件信息(记录)存放在不连续的物理块中,系统为每个文件建立一个专用数据结构——索引表,索引表中存放文件的逻辑块号和物理块号的对应关系

    1. 优点:
      既能顺序存取,又能直接存取。
      满足了文件动态增长、插入删除的要求。
      没有外碎片,外存空间利用率较高。
      缺点
      较多的寻道次数和寻道时间。
      索引表本身需要存储空间,同时对索引表的维护会增加系统开销。
    2. 索引表组织方式
      1. 链接文件方式:将多个索引表块按链接文件的方式串联起来
      2. 多重索引方式:将一个大文件的所有索引表(二级索引)的地址放在另一个索引表(一级索引)中。
        1. 多重索引优势
          1. 寻址空间较大,相比于链接文件,会大大减少读取对应物理块所需要的读盘次数(因为要从文件中读取索引项)

文件的目录

OS观点:文件包含文件控制块和文件体

文件控制块(FCB)的主要内容:

  • 文件名
    创建者
    文件物理位置信息:如索引表
    创建、修改时间、保存时间
    口令:用于对文件访问进行验证
    操作限制:如读、写、执行权限说明

文件目录提供的功能:

  • 实现“按名存取”。用户只须提供文件名,即可对文件进行存取。这是文件系统向用户提供的最基本的服务。
    提高对目录的检索速度。合理地组织目录结构,加快对目录的检索速度,从而加快对文件的存取速度。这是在设计一个大、中型文件系统时,所追求的主要目标。
    实现文件共享。在多用户系统中,应允许多个用户共享一个文件,以节省大量的存储空间并方便用户。
    解决文件重名问题。系统应允许不同用户对不同文件采用相同的名字,以便于用户按照自己的习惯命名和使用文件。

文件目录结构

l一级目录结构
  • 为外存上的全部文件设立一张平面(flat)的目录表,包含所有文件的FCB。每建立一个新文件即在目录中增加一个FCB,每当删除一个文件即抹去对应的FCB,当要访问一个文件时,先按文件名在目录中找到对应的文件FCB。
    为了快速查找到文件FCB,可按文件名进行Hash,或其它快速查找方式
  • 优点:简单
    缺点:
    1、查找速度慢
    2、不允许重名
    3、不便于实现文件共享
l二级目录结构
  • 设一个主目录MFD,为系统的每个用户设用户目录UFD,用户目录是用户所有文件FCB的集合,主目录中存放每个用户目录的用户目录名和UFD的索引表等(当我们把UFD看作是一个文件时,这个文件的内容是用户所有文件FCB集合,MFD中则包含每个UFD文件的FCB
  • 路径名
    将用户名与文件名连到一起组成路径名。例如:/songhong/test.c
多级目录——树形目录结构
  • 树状的多级目录结构
    任何一级目录中的FCB既可以描述次一级的子目录,又可以描述一个文件

  • 特点:

    • 利于文件分类,从文件路径名可看出文件类别。
      查找文件FCB耗费时间,要得到文件FCB,必须从根查起。
      唯一确定文件的路径名太长,故引入当前目录 概念,提供相对于当前目录的相对路径名可加速文件FCB的查找,进程控制块存有当前目录信息

  • 访问

  • 必须指出文件所在路径名:从根目录到该文件的路径上各级目录名的组合。也称为文件全名。
    例如:/usr/lib/man
    相对路径:设置一个“当前目录”(也叫“工作目录”),此时对于文件的查找是从当前目录中进行的。可以带来两点好处:
    用户使用更加方便
    检索效率更高

  • 优缺点

    l树形多级目录结构的优点

    提高了检索目录的速度。

    较好地解决了重名问题。

    l缺点

    不便于用户共享文件

无环图目录结构
当一个文件副本可以同时属于两个不同目录(类别)时,即同一个文件有二条路径名,或多条路径名时出现无环图目录结构。
特点:

方便文件共享,分类。
两个或多个FCB的一致性难保证,因此将FCB独立存放,引入带文件/目录名和FCB指针的目录项

image-20211130092527762

文件共享

    1. 指向同一个索引结点
  1. 符号链接

    1. 建立符号链文件,该文件内容为要访问文件的路径名

文件存储器空间布局与管理

空闲区表

image-20211203133204515

位示图

image-20211203133252860

image-20211203133418295

空闲块链

image-20211203134255752

image-20211203135715385

image-20211203140034820