操作系统作业 第37-40章

第四次作业

第37章

本章作业需要使用提供的disk.py程序。该程序可以模拟磁盘的工作。在默认情况下,磁盘调度方法为FIFO。对于时间的计算,假设旋转一度为1个时间单位,旋转完整一圈需要360个时间单位,而一个磁道上默认有12个扇区,每个扇区需要30个时间单元进行数据传输。磁道之间的距离默认为40单位,而寻道速度为每单位时间移动一单位距离,因此相邻磁道的寻道时间为40单位时间。-G可以看到磁头开始的位置为最外侧磁道的6号扇区,并可以进行寻道和旋转的模拟。起始情况如下图:

1.计算以下几组请求的寻道,旋转和传输时间

-a 0

磁头的起始位置在最外侧磁道,6号扇区,访问0号扇区,不需要寻道,只需要等待旋转延迟,需要等待旋转,然后传输数据。故寻道时间为0,旋转时间为165(从6号扇区中心旋转到0号扇区开始处),传输时间为30。s运行进行模拟,用时和预期相符。

-a 6

访问6号扇区,而起始位置已经在6号扇区的中心了。传输完整的数据,需要旋转345度,然后开始传输数据。因此寻道时间为0,旋转时间为345,传输时间为30。运行程序模拟,结果与预期相符。

-a 30

访问30号扇区,30号扇区在最内侧磁道,需要移动两个磁道的距离即80进行寻道,此时内侧磁道已经旋转80度,按照起始位置6号扇区与30号扇区在同一方向上,还需要旋转345-80=265度,才能开始访问30号扇区。因此对于该请求,寻道时间为80,旋转时间为265,传输时间为30。运行程序,结果符合预期。

-a 7,30,8

首先访问7号扇区,不需要进行寻道,只需要旋转15度就可以开始传输。30时间后准备访问30号扇区,需要移动到最内侧磁道,寻道时间为80,此时距离开始时已经过去了15+30+80=125,则等待30号扇区旋转的时间为345-125=220。传输结束后,又需要回到最外侧磁道访问8号扇区,此时已经过去了345+30+80=455,即此时在9号扇区(9号扇区数字+5度的位置),需要等待旋转310度,才可以传输8号扇区的数据。三次访问,寻道时间为160,旋转时间为15+220+310=545,传输时间为90。运行程序,结果符合预期。

-a 10,11,12,13

首先访问10,11号扇区,这两个扇区相邻,且与起始位置6号扇区在同一磁道,因此不需寻道,只需要等待旋转105度后就可以开始传输数据。处理完这两个扇区的请求后,需要移动到中间的磁道处理接下来的请求,寻道时间为40。移动到中间磁道时,时间已经过去了105+60+40=205,正在13号扇区(距离中心5度),重新回到12号扇区开始的位置,需要等待旋转320度,开始传输12号扇区的数据。因此完成该组请求,需要寻道时间40,等待时间105+320=425,传输时间为120。运行程序,结果符合预期。

2.更改寻道速度重新计算以上请求

对于请求队列-a 0,-a 6,起始位置在正确的磁道,不需要进行寻道,因此寻道时间为0,更改寻道时间,这两个请求的处理情况不会发生改变,因此只重新计算请求队列-a 30,-a 7,30,8,-a 10,11,12,13。

-a 30

寻道速率为2: 30号扇区在最内侧磁道,速率为2时,移动两个磁道的距离即80需要时间40,此时内侧磁道旋转40度,按照起始位置6号扇区与30号扇区在同一方向上,还需要旋转345-40=305度,开始访问30号扇区。因此对于该请求,寻道时间为40,旋转时间为305,传输时间为30。运行程序,结果符合预期。

寻道速率为4:移动磁道的时间缩短为20,内侧磁道还需要旋转345-20=325度,才能开始数据传输。寻道时间为20,旋转时间为325,传输时间为30。

寻道速率为8,10,40的情况与寻道速率为2,4的情况是类似的。等待30号扇区旋转到磁头位置需要旋转345度,而寻道时间一定小于这个时间,因此寻道时间+旋转时间=345。寻道速率越大,时间越短,而旋转时间越长。因此寻道速率为8时,寻道时间为10,旋转时间为335;寻道速率为10时,寻道时间为8,旋转时间为337;寻道速率为40时,寻道时间为2,旋转时间为343。而传输时间均为30。与题1中相比,寻道时间更短,旋转时间更长。

寻道速率为0.1的情况下,寻道时间需要800,转到30号扇区需要旋转360*2+345-800=265度。因此这种情况下寻道时间为800,旋转时间为265,传输时间仍为30。

-a 7,30,8

寻道速率为2:访问7号扇区旋转15度就可以开始传输。30时间后准备访问30号扇区,需要移动到最内侧磁道,寻道时间为40,此时距离开始时已经过去了15+30+40=85,则等待30号扇区旋转的时间为345-85=260。传输结束回到最外侧磁道访问8号扇区,此时已经过去了345+30+40=415,此时在8号扇区(8号扇区数字-5度的位置),需要等待旋转350度,传输8号扇区的数据。三次访问,寻道时间为80,旋转时间为15+260+350=625,传输时间为90。运行程序,结果符合预期。

更改寻道速率,按以上相同的方式,根据处理一个请求所用时间结合磁盘旋转的位置,计算各请求需要的寻道时间和等待时间,重新计算。处理请求需要两次寻道,可以直接根据速率计算,而旋转时间需要结合寻道时间判断旋转角度进行计算。结果如下:

寻道速率

寻道时间

旋转时间

与题1比较

4

0+20+20=40

15+280+10=305

寻道时间短,旋转时间短

8

0+10+10=20

15+290+20=325

寻道时间短,旋转时间短

10

0+8+8=16

15+292+22=329

寻道时间短,旋转时间短

40

0+2+2=4

15+298+28=341

寻道时间短,旋转时间短

0.1

0+800+800=1600

15+220+310=545

寻道时间长

根据以上结果可以发现,如果寻道很快,那么总是在旋转到合适的扇区之前到达正确磁道,但还是需要等待扇区旋转到磁头下,且寻道越快,旋转时间就越长,如果只需要旋转一周就可以得到需要的扇区,那么需要旋转的角度是固定的,即寻道时间+旋转时间=旋转固定角度需要的时间,因此在前几种情况中,寻道时间+旋转时间=345。而最后一种情况下寻道时间很长,需要旋转的角度产生了变化,因此时间也不同了。

最后一组数据计算结果与程序运行结果不同,程序中实际寻道用了801单位时间,但整体情况是一致的。

-a 10,11,12,13

寻道速率为2:访问10,11号扇区不需寻道,只需要等待旋转105度。处理完这两个扇区的请求后,需要移动到中间的磁道处理接下来的请求,寻道时间为20。移动到中间磁道时,时间已经过去了105+60+20=185,距离13号扇区10度,重新回到12号扇区开始的位置,需要等待旋转340度。因此完成该组请求,需要寻道时间40,等待时间105+340=445,传输时间为120。运行程序,结果符合预期。

对其他寻道速率下对该组请求的处理情况进行计算,结果如下:

寻道速率

寻道时间

旋转时间

与题1中比较

4

0+0+10+0=10

105+0+350+0=455

寻道时间短,旋转时间长

8

0+0+5+0=5

105+0+355+0=460

寻道时间短,旋转时间长

10

0+0+4+0=4

105+0+356+0=461

寻道时间短,旋转时间长

40

0+0+1+0=1

105+0+359+0=464

寻道时间短,旋转时间长

0.1

0+0+800+0=800

105+0+320+0=425

寻道时间长

运行程序,可以验证计算是正确的。同样的,最后一组数据与程序结果有1的偏差,程序寻道用了801时间。

3.改变旋转速率

直接运行程序获得结果:

-a 0

访问0号扇区,需要等待磁盘旋转165度。不同旋转速率下,寻道时间均为0,旋转时间和传输时间则根据不同的旋转速率,分别为:

旋转速率0.1:旋转时间1650,传输时间300

旋转速率0.5:旋转时间330,传输时间60

旋转速率0.01:旋转时间16500,传输时间3000

-a 6

与访问0号扇区类似,寻道时间为0,旋转时间发生变化:

旋转速率0.1:旋转时间3450,传输时间300

旋转速率0.5:旋转时间690,传输时间60

旋转速率0.01:旋转时间34500,传输时间3000

-a 30

先进行寻道,寻道时间均为80,然后根据旋转速率,旋转时间与传输时间分别为:

旋转速率0.1:旋转时间3370,传输时间300

旋转速率0.5:旋转时间610,传输时间60

旋转速率0.01:旋转时间34420,传输时间3000

-a 7,30,8

先访问7号扇区,需要旋转15度并等待传输完成,然后移动至内侧,根据此前旋转的时间,计算接下来旋转到30号扇区需要的时间,最后移动回外侧磁道,计算旋转到8号扇区需要的时间。其中寻道时间不随旋转速率变化而变化,均为160,结果如下:

旋转速率0.1:旋转时间3290,传输时间900

旋转速率0.5:旋转时间1250,传输时间180

旋转速率0.01:旋转时间34340,传输时间9000

-a 10,11,12,13

访问10,11号扇区后,移动到中间磁道,等待旋转,处理访问12,13扇区的请求。寻道时间均为40,旋转时间和传输时间如下:

旋转速率0.1:旋转时间4610,传输时间1200

旋转速率0.5:旋转时间890,传输时间240

旋转速率0.01:旋转时间46460,传输时间12000

根据以上几组请求的情况,旋转速率的减慢使旋转时间和传输时间大幅增加,尽管因为寻道很快,旋转角度可能小一些,但旋转时间还是很长。

4.更改调度策略为SSTF

默认情况下为FIFO调度策略,对于-a 7,30,8这一组请求,先处理对7号扇区的访问,然后访问最内侧磁道的30号扇区,最后回到外侧磁道访问8号扇区。需要进行2次寻道,如果在访问7号扇区后直接访问8号扇区,就可以减少一次寻道,且旋转时间也可以减少。

连续访问7,8号扇区只需要15的旋转时间,60的传输时间,然后移动到内侧磁道需要40 的寻道时间,与初始位置比较已旋转了155度,转到30号扇区开始的位置需要旋转时间345-155=190。按照7,8,30的顺序处理请求,共需要40的寻道时间,205的旋转时间,90的传输时间,整体时间比7,30,8的顺序大大减少。而使用最短寻道优先(SSTF)策略,就是按照这样的顺序处理请求的:

python3 ./disk.py -a 7,30,8 -p SSTF -G运行程序,使用最短寻道优先调度。

处理请求的顺序为7,8,30。

5.更改调度策略为SATF

更改调度策略为SATF,对于7,30,8这一组请求,处理顺序与使用SSTF的相同,为7,8,30,按这样的顺序处理请求,寻道和旋转时间都最短。

SSTF策略总是选择最近磁道上的请求进行处理,不考虑旋转时间。如果寻道时间较短,而最近磁道上的请求所需要的旋转时间很长,较远磁道上的旋转时间较短,先到较远的磁道处理请求,再回到最近的磁道处理请求才是更优的调度,即按照最短访问时间优先进行调度。因此这种情况下的一组请求,SATF会比SSTF表现更优。

磁头起始位置在6号扇区,假设有一个请求是访问中间磁道的18号扇区,另一个请求是内侧磁道的34号扇区。对于SSTF,处理请求顺序应该为18,34;SATF的请求顺序应该为34,18。由于先处理18号扇区的请求需要很长的等待时间,先处理34号扇区的SATF调度策略应该表现的比SSTF更好。运行程序,先采用SSTF调度策略:

处理请求顺序为18,34。旋转时间为355,寻道时间80,总时间为495。接下来使用SATF调度策略:

处理请求顺序为34,18。尽管因为没有选择最近的磁道处理请求,寻道时间变为了120,比SSTF更长,多了一次寻道,但由于旋转时间较短,只有195,最终处理请求的时间只有375,明显优于SSTF。

出现显著差异的原因在于SSTF优先选择最短寻道时间的请求,没有考虑旋转时间的情况。如果寻道时间相对旋转时间较短,而旋转时间很长,结合旋转时间情况考虑处理哪个请求的SATF就会表现的比只考虑寻道时间的SSTF更好。因此导致显著差异的条件为:一组请求中,寻道时间相对旋转时间较短。而且如果寻道时间比旋转时间越短,差异就会更加显著。

6.磁道偏斜

没有处理好10,11,12,13这一组请求的原因是,12,13号扇区在与10,11号扇区不同的磁道上,而他们在圆周上角度是连续的,处理完10,11号扇区的请求,需要一个寻道时间才能移动到12,13号扇区所在的磁道,而这两个扇区已经在寻道时旋转过去了,因此需要再等待一周的旋转才能处理请求。

解决这一问题的方法是引入磁道偏斜,让12,13号扇区在角度上与10,11号扇区不连续,而是偏斜一个角度,寻道时旋转过的小于这个角度,寻道完成后,使12号扇区很快就能转到磁头下进行请求处理,而不需要再旋转接近一圈,就能解决这个问题。默认寻道速率为1,相邻磁道间的移动需要40单位时间,取大于40角度的磁道偏斜,就可以使处理完11号扇区的请求后移动到中间磁道,刚好可以开始处理12号扇区的请求。一个扇区30度,则取2个扇区的磁道偏移,就可以解决问题。设置磁道偏斜为2,运行程序,引入磁道偏斜后,完成寻道时12号扇区还没有旋转过磁头,因此只要等待20的旋转时间,就可以处理12号扇区的请求。最终处理请求的时间为285,比不添加磁道偏斜的时间585少的多。

按照以上的分析,磁道偏斜的角度应该大于寻道时间内旋转过的角度,以减少请求的总时间。假设寻道速率为v,磁道间的距离为s,旋转速率为p,则寻道时间内旋转过的角度为p*(s/v)。假设一个磁道有n个扇区,则一个扇区的角度为360/n,偏斜磁道数设为x,则有p*(s/v) < (360/n)*x,x应该取使不等式成立的最小值。

因此可以使用以下公式计算磁道偏斜:

x > pns360v,x取使不等式成立的最小整数值

第38章

本章提供了一个RAID模拟器,可以模拟RAID的工作情况。通过指定参数可以指定工作负载为随机还是顺序,指定磁盘数、RAID级别和请求数及是否为写请求等。

1.基本RAID映射测试

RAID0

首先对RAID0映射进行测试。RAID0条带化中,连续的数据块轮流分布在不同的磁盘上,形成条带。因此对于RAID0的映射为:

磁盘号 = 地址%磁盘数

偏移 = 地址/磁盘数

使用5个请求进行测试,限制请求地址范围为20。根据模拟器生成的请求计算处理请求的磁盘并验证。运行:python3 ./raid.py -n 5 -L 0 -R 20进行测试。

根据映射进行计算,默认情况下磁盘数为4,结果为:

地址

磁盘号

偏移

16

0

4

8

0

2

10

2

2

15

3

3

9

1

2

加上-c进行验证,映射是正确的。

RAID1

考虑RAID1的映射。在RAID1中,相邻的两个磁盘为一个镜像对,保存了数据块的两个副本,在此基础上进行条带化。因此映射关系应该为:

磁盘号 = 2*地址%磁盘数(两个副本都可用)

偏移 = 2*地址/磁盘数

因为RAID1镜像中,数据块有两个副本,任意一个保存请求的数据块副本的磁盘都可以处理请求,选择哪个磁盘是随机的。同样使用5个请求进行测试,限制请求地址范围为20。根据模拟器生成的请求计算处理请求的磁盘并验证。运行:python3 ./raid.py -n 5 -L 1 -R 20进行测试。即仍然使用与上一组相同的请求,根据映射规则进行计算:

地址

磁盘号

偏移

16

0/1

8

8

0/1

4

10

0/1

5

15

2/3

7

9

2/3

4

加上-c进行验证,映射是正确的。

RAID4

对于RAID4,有一个磁盘用于存放奇偶校验块,其余磁盘以条带化的方式存放数据块。因此映射时每一个条带需要跳过一个磁盘:

磁盘号 = 地址%(磁盘数-1)

偏移 = 地址/(磁盘数-1)

同样使用以上的请求进行测试,地址和处理请求的磁盘情况为:

地址

磁盘号

偏移

16

1

5

8

2

2

10

1

3

15

0

5

9

0

3

加上-c验证,结果和计算结果相同。

RAID5

指定RAID5的左不对称布局,更改请求为顺序请求,生成20个请求,添加-c得出磁盘号和偏移,这样每个块的请求都可以找到RAID5中的一个位置,据此可以得出RAID5左不对称布局。运行:python3 ./raid.py -n 20 -L 5 -R 20 -5 LA -W seq -c,将结果填入RAID结构,可以得出RAID5左不对称的布局如下:

磁盘0

磁盘1

磁盘2

磁盘3

0

1

2

P1

3

4

P2

5

6

P3

7

8

P4

9

10

11

12

13

14

P5

15

16

P6

17

18

P7

19

20

以同样的方式,运行python3 ./raid.py -n 20 -L 5 -R 20 -5 LS -W seq -c,可以得到RAID5左对称布局如下:

磁盘0

磁盘1

磁盘2

磁盘3

0

1

2

P1

4

5

P2

3

8

P3

6

7

P4

9

10

11

12

13

14

P5

16

17

P6

15

20

P7

18

19

可以比较出RAID5左对称布局和左不对称布局的区别主要在数据块的分布上,左对称分布中, 数据块按照顺序分布在不同磁盘中,下一个数据块放在下一个磁盘上,直到最后一个磁盘。左不对称分布中,如果下一个块磁盘存放了校验块,就跳过下一个磁盘。

2.改变大块的大小

默认情况下大块只有1个块,如果将大块的大小变大,则在条带化时在磁盘上放一个大块大小的块,然后才移动到下一个磁盘进行放置。采用与上题中同样的方式,使用连续的请求,通过处理请求的磁盘号和偏移,可以得出RAID的映射。将大块的大小设置为两块的大小(8192),进行测试。

RAID0

python3 ./raid.py -n 20 -L 0 -R 20 -W seq -c -C 8192

映射情况如下:

磁盘0

磁盘1

磁盘2

磁盘3

0

2

4

6

1

3

5

7

8

10

12

14

9

11

13

15

RAID1:

python3 ./raid.py -n 20 -L 1 -R 20 -W seq -c -C 8192

相同的,可以得到RAID1大块为2块的映射情况,在镜像的基础上,每对镜像磁盘放置两块,然后移动到下一对镜像磁盘放置数据块。

磁盘0

磁盘1

磁盘2

磁盘3

0

0

2

2

1

1

3

3

4

4

6

7

5

5

7

7

RAID4

python3 ./raid.py -n 20 -L 4 -R 20 -W seq -c -C 8192

映射情况如下:

磁盘0

磁盘1

磁盘2

磁盘3

0

2

4

P

1

3

5

P

6

8

10

P

7

9

11

P

RAID5

python3 ./raid.py -n 20 -L 5 -R 20 -W seq -c -C 8192 -5 LA

映射情况如下:

磁盘0

磁盘1

磁盘2

磁盘3

0

2

4

P

1

3

5

P

6

8

P

10

7

9

P

11

12

P

14

16

13

P

15

17

改变大块大小没有改变各级RAID的布局规则,只需要将几个小块看成一个整体,映射情况没有发生改变。

3.反转问题

-r反转后,问题为给出磁盘号和磁盘偏移,计算地址。已知映射关系以及RAID布局的情况下,只需要从布局中找到RAID中某个磁盘特定位置保存的地址,或使用映射公式计算。

RAID0:

地址 = 磁盘数*偏移 + 磁盘号,据此就可以算出1中的地址。

RAID1:

地址 = (磁盘数*偏移 + 磁盘号)/2

RAID4:

地址 = (磁盘数-1)*偏移 + 磁盘号 (可能有1的偏差,因为不确定条带前面是否已有校验块)

RAID5:

可以根据不同的布局直接找到地址。

4.改变请求大小

本题要求改变请求的大小,并使用-r反转,即观察不同大小的请求磁盘I/O的情况以及不同RAID级别下磁盘I/O的情况。

8K

将请求的大小增大到8K,观察不同级别RAID的磁盘处理请求的情况。首先是RAID0级别,对于RAID0级别,请求大小为2个块,而一个磁盘单次处理一个块的请求,因此需要两次I/O完成8K的请求。运行:python3 ./raid.py -n 5 -L 0 -R 20 -r -S 8K,再加上-w 100观察写请求的处理情况:

读与写的情况是类似的,都需要2次I/O才能完成请求。

接下来查看RAID1级别的情况。对于读请求,RAID1只需要磁盘的2次读操作读出两个块的数据,对于写请求,由于每个块有两个副本,需要四次写操作才能完成请求。

对于RAID4,读请求的情况是一样的,不管是顺序读还是随机读,都是两次读完成。

 处理写请求不同,由于RAID4以校验块的方式提供冗余,在写入时,需要重写校验块。一种方式是减法奇偶校验,需要读取原来的数据块,原来的校验位,再写入新的块与校验位,共4次写。另一种是加法奇偶校验,读取另外的数据块(比如写数据块2,需要读数据块0和1),校验后将数据块和校验块并行写入。

可以看到,实际上只有一个写请求进行了8次写,剩下的请求都只需要4次写。这是因为写入时,对于同一条带上的连续两块进行写入,只需要读取一块,与其他两块(需要写入的2块)进行异或,然后将两块和校验块同时写入,即采用加法奇偶校验方法。因此只需要4次I/O。下面分别在磁盘阵列中查看请求写地址8的数据和请求写地址16的数据,写地址8的数据采用减法奇偶校验,因此通过8次写完成请求,而地址16的请求可以采用加法奇偶校验处理,只需要4次写。

磁盘0

磁盘1

磁盘2

磁盘3

0

1

2

P

3

4

5

P

6

7

8(读-写)

P(读-写)

9(读-写)

10

11

P(读-写)

12

13

14

P

15(读)

16 (写)

17(写)

P(写)

接下来考虑顺序写入,与随机写类似,加法奇偶校验写入操作数更少,就采用加法奇偶校验写入的方式进行写入,否则还是需要8次写(两个数据块不在同一条带上时,加法奇偶校验与减法奇偶校验写操作数相同):

RAID5与RAID4的读写情况都是相同的:

12K

接下来将请求大小修改为12K,对于RAID0与RAID1,只是需要多对一个块进行处理。因此与8K类似,RAID0需要3次I/O完成请求,RAID1需要3次读操作完成读请求,6次写操作完成写请求。

RAID4的随机读和顺序读也与8K类似,需要3次读完成。随机写有所不同,如果在同一个条带上进行写,那只需要三个块进行异或,然后一次将包括校验块在内的四个块全部写入,故需要4次写。如果有2个块在同一条带上,那么这两个块的写入可以采取加法奇偶校验(4次写操作),另一个单独在其他条带的块不论采用哪种方式,都需要4次写操作,故一共8次写操作。

RAID4顺序写时,写操作数明显减少了,因为每次请求都是对一个条带上的三个块进行写请求,可以采用全条带写入,即直接将三个块异或,然后全部和奇偶校验块一起写入。

RAID5的情况与RAID4是相同的。

16K

对于16K的请求,RAID0与RAID1的情况没有发生变化,只是需要多处理一个块。RAID0完成请求需要4次I/O。RAID1完成读需要4次读操作,完成写需要8次写操作。

RAID4的随机读和顺序读4次读操作完成。随机写时,有以下2种情况:

磁盘0

磁盘1

磁盘2

磁盘3

请求1

请求1

请求1

P

请求1

请求2

请求2

P

请求2

请求2

P

即一个请求分布在两个条带上,两个条带上的块数分别为3,1,另一种情况是两个条带上的块数分别为2,2。考虑3,1的情况,3个块在同一个条带上可以使用全条带写入(4次写),剩下一个块4次写单独处理,共8次写。另一种2,2的情况,每一个条带上采用加法奇偶校验,各需要4次写,故也需要8次写。

对于顺序写,情况是与随机写相同的,因为请求大小比1个条带的数据块要多。因此顺序写也是以上的两种模式。

RAID5与RAID4相同。

综合以上的所有分析,对于4个磁盘的情况下,请求块数越接近(小于等于)一个条带的块数,RAID4和RAID5的写性能更好。因为在这种情况下,加法奇偶校验可以比减法奇偶校验使用更少的写操作完成请求,最好的情况下,可以使用全条带写入直接完成写入,而不需要读取数据块。

5.100次读取,比较各级RAID性能

RAID0不提供冗余,因此为RAID性能上限,其他RAID级别的性能情况,具体见下表:

RAID0:python3 ./raid.py -L 0 -t -n 100 -c

RADI1: python3 ./raid.py -L 1 -t -n 100 -c

RADI4: python3 ./raid.py -L 4 -t -n 100 -c

RAID5: python3 ./raid.py -L 5 -t -n 100 -c

以上是随机读的情况,与表中的计算是相符的,RAID4的性能最差。如果是顺序读或者写请求,结果也都是和上表中的情况相符的。

第40章

本章提供的vsfs.py可以观察文件系统状态随各种操作发生而产生的改变。提供的基本操作为创建目录,创建文件,打开关闭文件,写文件,创建硬链接和删除硬链接。程序可以显示inode/数据位图,inodes和数据块来表现文件系统的状态。

1.运行模拟

以随机种子17运行模拟器,可得到文件系统状态的一系列变化,需要确认执行了什么操作。初始状态下只有根目录,没有其他文件。

下一个状态,多了一个inode,指向的文件类型为目录,占用了1号数据块,因此执行的操作是mkdir,创建了子目录u。

下一步操作后多出了一个inode,类型为文件,执行的操作为creat,创建一个新文件a。

接下来a的inode被删除,即删除了文件(unlink)。

下一步是创建根目录的子目录z和s。

接下来的三步,首先创建了文件x(在z中),然后x的引用+1,即创建了一个硬链接(在u中,与x都指向第4个inode),然后又删除了这个链接。

最后两步,向文件x中写入了数据v,然后又创建了一个新的文件b(在u中)。

采用其他种子模拟类似。根据目录及inode中的内容变化,可以看出是否创建了新的文件或子目录,从引用数可以看出文件的硬链接有几个,并可以通过数据块中目录的inode编号找到硬链接的位置。

2.显示操作,猜测状态

以种子21运行模拟器,在根据操作,推出文件系统的变化。

请求1为创建子目录o,则文件系统的变化应该如下:

inode bitmap      11000000

inodes              [d a:0 r:3][d a:1 r:2][][][][][][]

data bitmap        11000000

data                [(.,0) (..,0) (o,1)][(.,1) (..,0)][][][][][][]

请求2为创建文件b,只有inode被创建,还没有文件内容:

inode bitmap      11100000

inodes              [d a:0 r:3][d a:1 r:2][f a:-1 r:1][][][][][]

data bitmap        11000000

data                [(.,0) (..,0) (o,1) (b,2)][(.,1) (..,0)][][][][][][]

请求3在目录o下创建文件q,inode和目录内容都要更新:

inode bitmap      11110000

inodes              [d a:0 r:3][d a:1 r:2][f a:-1 r:1][ f a:-1 r:1][][][][]

data bitmap        11000000

data                [(.,0) (..,0) (o,1) (b,2)][(.,1) (..,0) (q,3)][][][][][][]

请求4,5向文件b和q写入了数据:

inode bitmap      11110000

inodes              [d a:0 r:3][d a:1 r:2][f a:2 r:1][ f a:3 r:1][][][][]

data bitmap        11110000

data                [(.,0) (..,0) (o,1) (b,2)][(.,1) (..,0) (q,3)][m][j][][][][]

请求6在目录o下创建了文件j:

inode bitmap      11111000

inodes              [d a:0 r:3][d a:1 r:2][f a:2 r:1][ f a:3 r:1][f a:-1 r:1][][][]

data bitmap        11110000

data                [(.,0) (..,0) (o,1) (b,2)][(.,1) (..,0) (q,3) (j,4)][m][j][][][][]

请求7删除了文件b的硬链接,由于引用只有1,该文件被删除:

inode bitmap      11011000

inodes              [d a:0 r:3][d a:1 r:2][][ f a:3 r:1][f a:-1 r:1][][][]

data bitmap        11010000

data                [(.,0) (..,0) (o,1)][(.,1) (..,0) (q,3) (j,4)][][j][][][][]

请求8向文件j写入了数据,假设使用刚刚释放的文件b的数据块:

inode bitmap      11011000

inodes              [d a:0 r:3][d a:1 r:2][][ f a:3 r:1][f a:2 r:1][][][]

data bitmap        11110000

data                [(.,0) (..,0) (o,1)][(.,1) (..,0) (q,3) (j,4)][g][j][][][][]

请求9在目录o下创建了文件x,假设重复使用已释放的inode:

inode bitmap      11111000

inodes              [d a:0 r:3][d a:1 r:2][f a:-1 r:-1][ f a:3 r:1][f a:2 r:1][][][]

data bitmap        11110000

data                [(.,0) (..,0) (o,1)][(.,1) (..,0) (q,3) (j,4) (x,2)][g][j][][][][]

最后在目录o下创建了子目录t:

inode bitmap      11111100

inodes              [d a:0 r:3][d a:1 r:3][f a:-1 r:-1][ f a:3 r:1][f a:2 r:1][d a:4 r:1][][]

data bitmap        11111000

data                [(.,0) (..,0) (o,1)][(.,1) (..,0) (q,3) (j,4) (x,2) (t,5)][g][j][(.,5) (..,1)][][][]

采用其他种子模拟的情况类似,对应各种操作更新文件系统的元数据和数据即可。根据分配情况来看,文件系统会选择最先找到的inode和数据块,即选择复用已经用过了但释放的最近的块用于inode和数据。

3.减少数据块

当数据块很少(2个时),创建目录会失败,因为创建目录需要分配数据块,而创建文件不会失败,因为创建文件只需要分配inode,不需要分配数据块,但文件不可以写入,没有可用数据块。硬链接和删除链接是可以的,因为链接只需要创建在目录下,指向文件的inode。因此最终只有文件的inode,根目录在文件系统中。

运行:python3 ./vsfs.py -n 100 -c -d 2 ,更换不同的随机种子,可以验证哪些操作是可行的。

创建文件和删除链接可行:

创建硬链接可行:

其他的操作都会失败。

4.减少inode

将inode减少到很少(3个),文件和目录都难以创建。如果有文件存在,硬链接和删除链接是可行的,对文件进行写也是可行的。下面是只有3个inode的情况,这种情况下,文件和子目录也可以创建,但同时只能有一个文件或子目录存在(最后一个inode不可用,因此除根目录的inode外只有一个可用inode)。

如果只有2个inode,文件和目录将都不可以创建,文件系统的最后一个inode块不可用,最终文件系统只有根目录。

猜你喜欢

转载自blog.csdn.net/Aaron503/article/details/130660872