一个操作系统的实现:第九章——文件系统

10 篇文章 7 订阅

IDE接口(Integrated Drive Electronics)是电子集成驱动器,是把“硬盘控制器”与“盘体”集成在一起的硬盘驱动器。把盘体与控制器集成在一起减少硬盘接口的电缆数目与长度,数据传输的可靠性得到增强,硬盘制造起来变得更容易的技术。IDE是一种计算机系统接口,主要用于硬盘CD-ROM,本意为“把控制器与盘体集成在一起的硬盘”。

ATA(英语:Advanced Technology Attachment,简称“ATA”)高技术配置,及后来的PATA(并行高技术配置,Parallel ATA)。一般说来,ATA是一个控制器技术,而IDE是一个匹配它的磁盘驱动器技术,但是两个术语经常可以互用。ATA是一个花费低而性能适中的接口,主要是针对台式机而设计的,销售的大多数ATA控制器和IDE磁盘都是更高版本的,称为ATA - 2和ATA - 3,与之匹配的磁盘驱动器称为增强的IDE。

SATA:
串行ATA(Serial ATA: Serial Advanced Technology Attachment)是一种计算机总线,负责主板和大容量存储设备(如硬盘光盘驱动器)之间的数据传输,主要用于个人计算机。串行ATA与串列SCSI(SAS: Serial Attached SCSI)的两者排线兼容,SATA硬盘可接上SAS接口。

对硬盘控制器的操作仍是通过I/O端口来进行,这些端口分为两组,它们对应命令块寄存器(Command Block Registers)和控制块寄存器(ControlBlock Register),如下所示。

表中的Primary和Secondary指的是ATA接口通道(Channel),通俗地说就是主板上的IDE口。一个普通的PC主板上通常有两个IDE口,分别对应两个IDE通道:Primary和Secondary,它们有时也被标注为IDE0和IDE1。每个IDE通道又能连接两个设备,称为主设备(Master)和从设备(Slave)。对不同的IDE通道的访问是通过I/O端口来区分的,对同一IDE通道上的主从设备的访问是通过Device寄存器上的第4位的值来区分的──第4位为0时操作主设备,为1时操作从设备。事实上一个机器不只允许有两个IDE通道,但超过两个的情况非常罕见。

对硬盘的操作并不复杂,只需先往命令块寄存器(Command Block Registers)写入正确的值,再通过控制块寄存器(Control Block Register)发送命令就可以了。

例如:向硬盘驱动器发送一个IDENTIFY命令,这个命令可用来获取硬盘参数。向硬盘发送IDENTIFY命令很简单,只需要通过Device寄存器的第4位指定驱动器──0表示Master,1表示Slave──然后往Command寄存器写入十六进制ECh就可以。硬盘准备好参数之后,会产生一个中断,这时我们就可以通过Data寄存器读取数据了。参数有很多,总共是256个字(WORD)。

Device寄存器的格式,如下图所示。

可以看到,寄存器主要有三部分:LBA模式位、DRV位和低四位。我们之前已经提到两次,DRV位(第4位)用于指定主盘或从盘,0表示主盘,1表示从盘。LBA模式位用于指定操作模式,当此位为0时,对磁盘的操作使用CHS模式,也即用“柱面/磁头/扇区号”来定位扇区;当此位为1时,对磁盘的操作使用LBA(Logical Block Address)模式。由于现代硬盘都支持LBA模式,在本书中我们都使用LBA 模式。寄存器的低四位,在CHS模式中表示磁头号,在LBA模式中表示LBA的24到27位。也就是说,LBA的地址被拆分成了四部分,第0到7位由LBA Low寄存器指定,第8到15位由LBA Mid寄存器指定,第16到23位由LBAHigh寄存器指定。整个LBA是28位的,经过计算可得知,2^28 =268435456,这么多个扇区意味着128GB的容量,这也是28位LBA的最大寻址能力。

可是目前市面上的硬盘容量早就超过128GB了,怎么突破限制呢?原理也很简单,每次读写的时候,三个寄存器──LBA Low、LBA Mid、LBA High──每个使用两次,这样就相当于有了六个寄存器来存储地址,这就是LBA48(ATA-6开始支持)。48位LBA的寻址上限为128PB,我们觉得并希望它是足够了,但谁知道呢,或许不久以后每个寄存器将不得不使用三次──我们已经见到太多例子,人们不停在想办法突破自己之前设下的限制,但当下一次做决定时,还是会低估技术的发展速度。

 Status Register:

 Device Control Register:

一个简单的文件系统大致需要这么几个要素:
要有地方存放Metadata;
要有地方记录扇区的使用情况;
要有地方来记录任一文件的信息,比如占用了哪些扇区等;
要有地方存放文件的索引。

简图如下:

可以看到,总体上来看,它几乎是把前述的各要素一字排开:
要有地方存放Metadata——占用整整一个扇区的superblock;
要有地方记录扇区的使用情况——sectormap;
要有地方来记录任一文件的信息,比如占用了哪些扇区等──inode map以及被称作inode_array的i-node真正存放地;
要有地方存放文件的索引──root数据区。

superblock通常也叫超级块,关于文件系统的Metadata我们统统记在这里。sector map是一个位图,它用来映射扇区的使用情况,用1表示扇区已被使用,0表示未使用。i-node是UNIX世界各种文件系统的核心数据结构之一,我们把它借用过来。每个i-node对应一个文件,用于存放文件名、文件属性等内容,inode_array就是把所有i-node都放在这里,形成一个较大的数组。而inode map就是用来映射inode_array这个数组使用情况的一个位图,用法跟sector map类似。root数据区类似于FAT12的根目录区,但本质上它也是个普通文件,由于它是所有文件的索引,所以我们把它单独看待。为了简单起见,我们的文件系统暂不支持文件夹,也就是说用来表示目录的特殊文件只有这么一个。这种不支持文件夹的文件系统,其实也不是我们的首创,历史上曾经有过,而且这种文件系统还有个名字,叫做扁平文件系统(Flat File System)。

硬盘分区表其实是一个结构体数组,数组的每个成员是一个16字节的结构体,它的构成如下图所示。

这个数组位于引导扇区的1BEh处,共有四个成员──因为IBM当时觉得一台PC最多会装四个操作系统。现在我们的计算机中每块硬盘经常划分成不止四个分区,这是因为每个主分区可以进一步分成多个逻辑分区。

逻辑硬盘:

 /sbin/fdisk 80m.img
… … …
Command (m for help): x ←↪ 进入 extra functionality 菜单
Expert command (m for help): c ←↪ 设置柱面数
Number of cylinders (1-1048576): 162 ←↪ 柱面数为 162
Expert command (m for help): h ←↪ 设置磁头数
Number of heads (1-256, default 255): 16 ←↪ 磁头数为 16
Expert command (m for help): r ←↪ 回到主菜单
Command (m for help): n ←↪ 新建分区
Command action
e extended
p primary partition (1-4)
p ←↪ 主分区
Partition number (1-4): 1 ←↪
First cylinder (1-162, default 1):←↪
Using default value 1
Last cylinder or +size or +sizeM or +sizeK (1-162, default 162): 20 ←↪
Command (m for help): n ←↪ 新建分区
Command action
e extended
p primary partition (1-4)
e ←↪ 扩展分区
Partition number (1-4): 2 ←↪
First cylinder (21-162, default 21):←↪
Using default value 21
Last cylinder or +size or +sizeM or +sizeK (21-162, default 162):←↪
Using default value 162
Command (m for help): n ←↪ 新建分区
Command action
l logical (5 or over)
p primary partition (1-4)
l ←↪ 逻辑分区
First cylinder (21-162, default 21):←↪
Using default value 21
Last cylinder or +size or +sizeM or +sizeK (21-162, default 162): 60 ←↪
Command (m for help): n ←↪ 新建分区
Command action
l logical (5 or over)
p primary partition (1-4)
l ←↪ 逻辑分区
First cylinder (61-162, default 61):←↪
Using default value 61
Last cylinder or +size or +sizeM or +sizeK (61-162, default 162): 90 ←↪
Command (m for help): n ←↪ 新建分区
Command action
l logical (5 or over)
p primary partition (1-4)
l ←↪ 逻辑分区
First cylinder (91-162, default 91):←↪
Using default value 91
Last cylinder or +size or +sizeM or +sizeK (91-162, default 162): 132 ←↪
Command (m for help): n ←↪ 新建分区
Command action
l logical (5 or over)
p primary partition (1-4)
l ←↪ 逻辑分区
First cylinder (133-162, default 133):←↪
Using default value 133
Last cylinder or +size or +sizeM or +sizeK (133-162, default 162): 160 ←↪
Command (m for help): n ←↪ 新建分区
Command action
l logical (5 or over)
p primary partition (1-4)
l ←↪ 逻辑分区
First cylinder (161-162, default 161):←↪
Using default value 161
Last cylinder or +size or +sizeM or +sizeK (161-162, default 162):←↪
Using default value 162
Command (m for help): p ←↪ 打印分区表
Disk 80m.img: 0 MB, 0 bytes
16 heads, 63 sectors/track, 162 cylinders
Units = cylinders of 1008 * 512 = 516096 bytes
Device Boot Start End Blocks Id System
80m.img1 1 20 10048+ 83 Linux
80m.img2 21 162 71568 5 Extended
⇒ 80m.img5 21 60 20128+ 83 Linux
80m.img6 61 90 15088+ 83 Linux
80m.img7 91 132 21136+ 83 Linux
80m.img8 133 160 14080+ 83 Linux
80m.img9 161 162 976+ 83 Linux
Command (m for help): t ←↪ 更改分区类型
Partition number (1-9): 5 ←↪ 选80m.img5
Hex code (type L to list codes): L ←↪ 列出已知类型(受输出宽度影响,有些类型名被截断)
0 Empty 1e Hidden W95 FAT1 80 Old Minix be Solaris boot
1 FAT12 24 NEC DOS 81 Minix / old Lin bf Solaris
2 XENIX root 39 Plan 9 82 Linux swap / So c1 DRDOS/sec
3 XENIX usr 3c PartitionMagic 83 Linux c4 DRDOS/sec
4 FAT16 <32M 40 Venix 80286 84 OS/2 hidden C: c6 DRDOS/sec
5 Extended 41 PPC PReP Boot 85 Linux extended c7 Syrinx
6 FAT16 42 SFS 86 NTFS volume set da Non-FS data
7 HPFS/NTFS 4d QNX4.x 87 NTFS volume set db CP/M / CTOS
8 AIX 4e QNX4.x 2nd part 88 Linux plaintext de Dell Utility
9 AIX bootable 4f QNX4.x 3rd part 8e Linux LVM df BootIt
a OS/2 Boot Manag 50 OnTrack DM 93 Amoeba e1 DOS access
b W95 FAT32 51 OnTrack DM6 Aux 94 Amoeba BBT e3 DOS R/O
c W95 FAT32 (LBA) 52 CP/M 9f BSD/OS e4 SpeedStor
e W95 FAT16 (LBA) 53 OnTrack DM6 Aux a0 IBM Thinkpad hi eb BeOS fs
f W95 Ext'd (LBA) 54 OnTrackDM6 a5 FreeBSD ee EFI GPT
10 OPUS 55 EZ-Drive a6 OpenBSD ef EFI
11 Hidden FAT12 56 Golden Bow a7 NeXTSTEP f0 Linux/PA-RISC
12 Compaq diagnost 5c Priam Edisk a8 Darwin UFS f1 SpeedStor
14 Hidden FAT16 <3 61 SpeedStor a9 NetBSD f4 SpeedStor
16 Hidden FAT16 63 GNU HURD or Sys ab Darwin boot f2 DOS secondary
17 Hidden HPFS/NTF 64 Novell Netware b7 BSDI fs fd Linux raid
18 AST SmartSleep 65 Novell Netware b8 BSDI swap fe LANstep
1b Hidden W95 FAT3 70 DiskSecure Mult bb Boot Wizard hid ff BBT
1c Hidden W95 FAT3 75 PC/IX
Hex code (type L to list codes): 99 ←↪ 将99h作为Orange'S FS的system id
Changed system type of partition 5 to 99 (Unknown)
Command (m for help): a ←↪ 设置可启动标志
Partition number (1-9): 5 ←↪ 选80m.img5
Command (m for help): p ←↪ 再次打印分区表
Disk 80m.img: 0 MB, 0 bytes
16 heads, 63 sectors/track, 162 cylinders
Units = cylinders of 1008 * 512 = 516096 bytes
Device Boot Start End Blocks Id System
80m.img1 1 20 10048+ 83 Linux
80m.img2 21 162 71568 5 Extended
⇒ 80m.img5 * 21 60 20128+ 99 Unknown
80m.img6 61 90 15088+ 83 Linux
80m.img7 91 132 21136+ 83 Linux
80m.img8 133 160 14080+ 83 Linux
80m.img9 161 162 976+ 83 Linux
Command (m for help): w ←↪ 写入“磁盘”
… … …

在这里我们把一个80MB的硬盘映像分成了一个主分区和一个扩展分区,扩展分区中又分成了五个逻辑分区。我们将来把Orange'S装在第一个逻辑分区上,也就是标为80m.img5的分区。我们先是把它的分区类型(SystemID)改成99h,又为它设定了“可启动”标志。在设置分区类型时,我们先是列出了已知的类型,然后选定还未使用的99h作为我们文件系统的SystemID。

 扩展分区和逻辑分区:

设备号:

读者一定注意到了,在上图中每个分区都标上了一个分区号,分别是1、2、5、6、7、8、9。这是为了跟fdisk中打印出来的分区情况相一致。这里的编号规则在Linux世界是通行的,1~4这四个数字为主引导扇区中的分区表项所用,从5开始依次表示逻辑分区。在我们的例子中,主引导扇区中有两个表项,对应一个主分区和一个扩展分区,即80m.img1和80m.img2,扩展分区中有5个逻辑分区,从80m.img5到80m.img9。
其实1、2、5~9等这些数字有个名称,叫做次设备号。其作用是给每个设备(分区)起一个名字,这样驱动程序就能方便地管理它们。另外还有个我们没讲过的主设备号,它的作用是给每一类设备一个名字,以方便管理。举个例子,假设我们的计算机内有三块硬盘和两个软盘。对用户而言,操作硬盘和软盘上文件的区别可能仅在于路径不同,但对于操作系统,硬盘和软盘需要不同的驱动程序,所以不同类别的硬件需要区别对待,这就是主设备号存在的理由。同时,硬盘有多个,而且每个硬盘上可能有多个分区,对这些分区,又需要区别对待,于是又用到了次设备号。简单来说,主设备号告诉操作系统应该用哪个驱动程序来处理,次设备号告诉驱动程序这是具体哪个设备。

文件系统通常有两个含义:
用于存储和组织计算机文件数据的一套方法
存在于某介质上的具备某种格式的数据

创建文件系统分这么几个部分:
向硬盘驱动程序索取ROOT_DEV的起始扇区和大小;
建立超级块(Super Block);
建立inode-map;
建立sector-map;
写入inode_array;
建立根目录文件。

文件描述符((file descriptor):
下图描述的是我们即将使用的文件操作方案。每个进程表中都将增加一个filp数组,其成员是指向file descriptor(下文简称fd)的指针。每一个使用中的fd都有一个指针指向一个inode结构体,而由这个inode结构体可以找到具体的文件。

一个文件在文件系统中涉及的要素有五个:
文件内容(数据)所占用的扇区;
i-node;
i-node在inode-map中占用的一位;
数据扇区在sector-map中占用的一位或多位;
文件在目录中占有的目录项(direntry)。

相应地,我们创建一个文件,需要做以下几项工作:
为文件内容(数据)分配扇区;
在inode_array中分配一个i-node;
在inode-map中分配一位;
在sector-map中分配一位或多位;
在相应目录中写入一个目录项(direntry)。

删除是添加的反过程,所以要删除文件,我们需要做以下工作:
释放inode-map中的相应位。
释放sector-map中的相应位。
删除根目录中的目录项。

 如今的内存的使用情况:

为文件系统添加一个系统调用xxx( )的步骤大致上有这些:
1. 定义一种消息,比如MMM(可参照incluse/sys/const.h中UNLINK的定义方法)。
2. 写一个函数来处理MMM消息(可参照fs/link.c中do_unlink( )的代码)。
3. 修改task_fs( ),增加对消息MMM的处理。
4. 写一个用户接口函数xxx( )(可参照lib/unlink.c中unlink( )的代码)。

  • 0
    点赞
  • 0
    评论
  • 2
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值