磁盘的物理组成
-
盘面:
-
磁盘由多个盘面组成,每个盘面上都有数据存储的区域。
-
-
磁道:
-
每个盘面上都有若干个同心圆,这些同心圆称为磁道。磁道是数据存储的路径。
-
-
扇区:
-
磁道被进一步划分为若干个扇区,扇区是磁盘的最小访问单位。
-
扇区大小通常为512字节。
-
磁盘的io流程
该幻灯片描述了磁盘的输入/输出(I/O)过程,具体步骤如下:
-
开始使用磁盘:
-
首先,系统需要通过IDE控制器与磁盘建立连接,开始磁盘的I/O操作。
-
-
磁盘I/O过程:
-
磁盘的I/O过程包括以下几个步骤:控制器、寻道、旋转、传输。
-
-
寻道:
-
控制器发送指令,使磁头移动到正确的磁道上。这是为了定位到数据所在的物理位置。
-
-
旋转:
-
磁盘旋转,使得目标扇区移动到磁头下方。这个过程需要等待磁盘旋转到正确的位置,可能会有一定的延迟。
-
-
传输:
-
一旦目标扇区位于磁头下方,数据就可以从磁盘读取到内存中,或者从内存写入到磁盘中。
-
-
内存缓存:
-
读取或写入的数据首先会进入内存缓存。对于读取操作,数据从磁盘读出后存储在内存缓存中;对于写操作,数据首先写入内存缓存,然后再从缓存写入磁盘。
-
使用磁盘
柱面(Cylinder)
柱面是磁盘上所有盘面中具有相同径向位置的磁道的集合。
当计算机需要读取或写入数据时,它会根据柱面号、磁头号和扇区号来确定目标数据的位置。
通过控制磁头的移动和盘片的旋转,计算机可以准确地定位到特定柱面上的特定扇区,进行数据的读写操作。
磁头(Head)
每个盘面对应一个磁头。
所有的磁头都是连在同一个磁臂上的,因此所有磁头只能“共进退”。
每个磁头上都有读和写的操作装置,用于读取和写入数据。
磁头臂是支持磁头的可移动臂,通过电动机或电磁力控制,可以使磁头在盘片上移动到不同的磁道位置。
扇区(Sector)
每个盘片被划分为一个个磁道,每个磁道又划分为一个个扇区。
扇区是磁盘的最小访问单位,通常为512字节。
在读取或写入数据时,磁头需要准确地定位到相应的扇区。磁盘驱动器在向磁盘读取和写入数据时,要以扇区为单位。
代码分析
从提供的幻灯片内容中,我们可以提取出两个函数的代码,它们是 do_hd_request
和 hd_out
。以下是提取的代码和总结:
提取的代码
void do_hd_request(void) {...hd_out(dev, nsect, sec, head, cyl, WIN_WRITE, ...); // 调用hd_out函数port_write(HD_DATA, CURRENT->buffer, 256); // 将数据写入硬盘
}
void hd_out(drive, nsect, sec, head, cyl, cmd...) {port = HD_DATA; // 数据寄存器端口(0x1f0)outb_p(nsect, ++port); // 输出扇区数outb_p(sec, ++port); // 输出起始扇区号outb_p(cyl, ++port); // 输出柱面号outb_p(cyl >> 8, ++port); // 输出柱面号的高字节outb_p(0xA0 | (drive << 4) | head, ++port); // 输出驱动器和磁头信息outb_p(cmd, ++port); // 输出命令
}
代码总结
-
do_hd_request
函数:-
这个函数处理硬盘的I/O请求。
-
它调用
hd_out
函数来设置硬盘控制器的参数,包括设备号(dev)、扇区数(nsect)、扇区号(sec)、磁头号(head)、柱面号(cyl)等。 -
然后,它使用
port_write
函数将数据从内存缓冲区(CURRENT->buffer
)写入硬盘,这里写入的数据量为256字节。
-
-
hd_out
函数:-
这个函数负责将控制命令和参数输出到硬盘控制器。
-
它首先设置数据寄存器端口(
HD_DATA
)。 -
然后,它使用
outb_p
函数依次输出扇区数、扇区号、柱面号、柱面号的高字节、驱动器和磁头信息以及命令。 -
这些参数用于控制硬盘的读写操作,例如移动磁头到指定的柱面和磁头位置,然后读取或写入指定的扇区。
-
这些代码是磁盘驱动程序的核心部分,它们实现了操作系统与硬盘硬件之间的直接交互,是文件系统和数据存储管理的基础。
如何通过盘块号读写磁盘
盘块
盘块(Block)是文件系统中用于数据存储和管理的一个逻辑概念,它是文件系统中数据存储的基本单位。盘块是逻辑上的划分,不同于磁盘物理结构中的扇区(Sector)、柱面(Cylinder)和磁头(Head)等概念。以下是盘块的详细解释:
-
盘块号:
-
每个盘块都有一个唯一的标识符,称为盘块号(Block Number)。盘块号用于在文件系统中定位和访问特定的盘块。
-
-
盘块与扇区的关系:
-
盘块通常由一个或多个扇区组成。一个扇区是磁盘上最小的物理存储单位,通常大小为512字节。
-
文件系统将一个或多个连续的扇区组合成一个盘块,以提高数据管理的效率。
-
-
盘块的分配:
-
文件系统使用盘块分配表(Block Allocation Table, BAT)或inode(索引节点)等数据结构来记录每个文件占用的盘块信息。
-
当文件被创建或修改时,文件系统会分配新的盘块或更新现有文件的盘块信息。
-
-
盘块的优缺点:
-
优点:简化了文件数据的管理,提高了数据存储和检索的效率。
-
缺点:如果文件大小不是盘块大小的整数倍,最后一个盘块可能会有未使用的空间,导致一定的空间浪费。就是用空间换时间
-
为什么使用盘块
-
磁盘访问时间的组成:
-
磁盘访问时间包括写入控制器时间、寻道时间、旋转时间和传输时间。
-
寻道时间:磁头移动到目标磁道的时间,通常在12毫秒到8毫秒之间。
-
旋转时间:磁盘旋转到目标扇区的时间,对于7200转/分钟的硬盘,半周大约需要4毫秒。
-
传输时间:数据从磁盘传输到内存的时间,大约0.3毫秒(50MB/秒)。
-
-
盘块相邻的优势:
-
相邻的盘块在物理位置上接近,因此可以快速连续读出,减少了寻道时间和旋转时间,提高了磁盘访问效率
-
优点分析
-
提高效率:通过减少寻道时间和旋转时间,提高了磁盘访问的速度,从而提高了整体的系统性能。
-
抽象层次:操作系统通过提供这一层抽象,隐藏了磁盘的物理访问细节,使得上层应用程序可以更加方便地使用磁盘资源。
如何编址?为什么这样编址?
-
如何编址:磁盘驱动通过算法将盘块号映射到CHS地址。这通常涉及到磁盘的几何结构和盘块的布局。
-
为什么这样编址:这种编址方式是为了优化磁盘访问效率。通过将相邻的盘块放在磁盘上的相邻位置,可以减少寻道时间和旋转时间,从而提高数据访问速度。
扇区号的获得
从CHS到扇区号
-
CHS地址转换:磁盘的物理地址通常由柱面号(Cylinder)、磁头号(Head)和扇区号(Sector)组成。幻灯片中提到的公式
Cx(HeadsxSectors) + HxSectors + S
用于计算从CHS地址到扇区号的转换。-
C
:柱面号 -
Heads
:磁盘上的磁头数 -
Sectors
:每个磁道上的扇区数 -
H
:磁头号 -
S
:扇区号
-
磁盘请求的创建和处理过程
从提供的幻灯片内容中,我们可以提取出两个函数的代码,它们是 make_request
和 do_hd_request
。以下是提取的代码和分析:
提取的代码
// 创建一个磁盘请求
static void make_request()
{struct request *req;req = request + NR_REQUEST;req->sector = bh->b_blocknr << 1;add_request(major + blk_dev, req);
}
// 处理硬盘请求
void do_hd_request(void)
{unsigned int block = CURRENT->sector;asm volatile ("divl %4, %%eax;" // block / sect (每个磁头的扇区数)"=a" (block), // 输入:eax = 被除数"=d" (sec), // 输出:edx = 余数(扇区号)"0" (block), // 输入:eax = 被除数"1" (0), // 输入:edx = 0(初始化为0)"r" (hd_info[dev].sect) // 输入:ecx = 除数(每个磁头的扇区数));asm volatile ("divl %4, %%eax;" // (block / sect) / head (磁头数)"=a" (cyl), // 输出:eax = 商(柱面号)"=d" (head), // 输出:edx = 余数(磁头号)"0" (block), // 输入:eax = 被除数"1" (0), // 输入:edx = 0(初始化为0)"r" (hd_info[dev].head) // 输入:ecx = 除数(磁头数));hd_out(dev, nsect, sec, head, cyl, WIN_WRITE, ...);...
}
代码分析
-
make_request
函数:-
这个函数用于创建一个新的磁盘请求。
-
它分配一个新的请求结构体
req
,并设置请求的扇区号req->sector
。 -
bh->b_blocknr << 1
:将块号左移一位,为了将块号转换为扇区号(假设每个块由两个扇区组成)。 -
add_request
:将新创建的请求添加到请求队列中。
-
-
do_hd_request
函数:-
这个函数处理硬盘请求,将盘块号转换为CHS地址,并调用
hd_out
函数执行实际的磁盘操作。 -
CURRENT->sector
:获取当前请求的扇区号。 -
使用内联汇编(
asm volatile
)进行除法运算,将扇区号转换为柱面号(cyl)、磁头号(head)和扇区号(sec)。-
第一个除法运算计算扇区号(
sec
)。 -
第二个除法运算计算柱面号(
cyl
)和磁头号(head
)。
-
-
hd_out
:执行实际的磁盘操作,包括寻道、旋转和数据传输。
-
总结
这段代码展示了Linux 0.11内核中磁盘请求的创建和处理过程。make_request
函数负责创建新的磁盘请求,而 do_hd_request
函数负责将盘块号转换为CHS地址,并执行实际的磁盘操作。
通过内联汇编进行除法运算,实现了从盘块号到CHS地址的转换,这是磁盘驱动程序中的关键步骤。
多个进程使用磁盘
多进程通过队列使用磁盘
-
请求队列:
-
当多个进程需要访问磁盘时,它们的请求被放入一个请求队列中。这个队列管理所有磁盘访问请求,确保它们有序地被处理。
-
-
磁盘驱动:
-
磁盘驱动负责从请求队列中取出请求,并将其转换为磁盘控制器可以理解的CHS(柱面、磁头、扇区)地址。
-
-
磁盘控制器:
-
磁盘控制器根据磁盘驱动提供的CHS地址执行实际的磁盘操作,如寻道、旋转和数据传输。
-
磁盘调度
-
调度目标:
-
磁盘调度的主要目标是最小化平均访问延迟。这意味着调度算法需要尽可能减少磁盘访问请求的等待时间。
-
-
调度时主要考察的因素:
-
寻道时间:磁头移动到目标磁道的时间,这是磁盘访问时间中的主要部分。
-
旋转时间:磁盘旋转到目标扇区的时间。
-
传输时间:数据从磁盘传输到内存的时间。
-
-
调度算法:
-
FCFS(First-Come, First-Served):最简单的调度算法,按照请求到达的顺序处理。虽然公平,但可能不是最高效的,因为它不考虑磁头的当前位置或请求的物理位置。
-
更复杂的算法:如SSTF(Shortest Seek Time First)、SCAN(Elevator Algorithm)等,这些算法试图通过优化磁头移动路径来减少寻道时间,从而提高整体性能。
-
FCFS
-
最直观、最公平的调度:
-
FCFS算法按照请求到达的顺序处理,确保每个请求都能被公平地处理。
-
-
实例分析:
-
磁头开始位置为53。
-
请求队列为:98, 183, 37, 122, 14, 124, 65, 67。
-
-
磁头移动:
-
FCFS算法导致磁头共移动了640个磁道。
-
磁头在移动过程中处理了经过的请求。
-
-
磁头在长途奔袭:
-
图中显示了磁头在处理请求时的移动路径,磁头需要在磁盘上进行大量的移动,这可能导致效率低下。
-
-
效率问题:
-
FCFS算法虽然公平,但可能导致磁头在磁盘上进行大量的寻道操作,增加了寻道时间和旋转时间,从而降低了磁盘的整体性能。
-
SSTF
SSTF(Shortest Seek Time First,最短寻道时间优先)磁盘调度算法。SSTF算法是一种优化磁盘访问时间的算法,它选择距离当前磁头位置最近的请求进行处理,以减少磁头移动的距离。以下是对幻灯片内容的分析:
-
算法原理:
-
SSTF算法选择距离当前磁头位置最近的请求进行处理,以减少寻道时间。
-
这种方法可以显著减少磁头移动的总距离,从而提高磁盘访问效率。
-
-
实例分析:
-
磁头开始位置为53。
-
请求队列为:98, 183, 37, 122, 14, 124, 65, 67。
-
-
磁头移动:
-
在这个实例中,SSTF算法导致磁头共移动了236个磁道(4+53+169)。
-
相比FCFS算法的640个磁道,SSTF算法显著减少了磁头移动的距离。
-
-
效率提升:
-
通过优先处理距离当前磁头位置最近的请求,SSTF算法可以更快地响应请求,减少等待时间。
-
-
饥饿问题:
-
SSTF算法存在饥饿问题,即远离当前磁头位置的请求可能会长时间得不到处理。
-
如果在处理183号请求之前,又来了一些中间磁道的请求,那么183号请求可能会被推迟处理,导致延迟。
-
SCAN
SCAN磁盘调度算法,也称为电梯算法,它是一种常见的磁盘调度策略,旨在优化磁盘的寻道操作,减少寻道时间。
-
算法原理:
-
SCAN算法模拟电梯的运行方式,磁头从一个方向开始移动,直到达到最后一个请求,然后改变方向,继续处理另一方向的请求。
-
这种算法确保每个请求最终都会被处理,避免了SSTF算法中可能出现的饥饿问题。
-
-
实例分析:
-
磁头开始位置为53。
-
请求队列为:98, 183, 37, 122, 14, 124, 65, 67。
-
-
磁头移动:
-
在这个实例中,SCAN算法导致磁头共移动了236个磁道(53+183)。
-
与SSTF算法相比,SCAN算法在处理请求时更加公平,因为它确保了磁头会遍历所有请求。
-
-
公平性:
-
SCAN算法通过确保每个方向上的请求都被处理,提高了算法的公平性。
-
-
效率:
-
SCAN算法通过减少磁头的来回移动,提高了磁盘访问的效率。
-
与SSTF相比,SCAN算法在处理大量随机分布的请求时,通常能提供更好的性能。
-
C-SCAN
这张幻灯片介绍了C-SCAN(Circular SCAN)磁盘调度算法,这是一种类似于电梯算法的磁盘调度策略,但在到达一端后直接移动到另一端,而不是改变方向。以下是对幻灯片内容的分析和总结:
-
算法原理:
-
C-SCAN算法从磁头的当前位置开始,向一个方向移动,处理所有请求,到达磁盘的一端后,直接移动到另一端,然后继续处理请求。
-
这种算法确保了两端的请求都能被快速处理。
-
-
实例分析:
-
磁头开始位置为53。
-
请求队列为:98, 183, 37, 122, 14, 124, 65, 67。
-
-
磁头移动:
-
在这个实例中,C-SCAN算法导致磁头共移动了157+200个磁道。
-
其中200个磁道是磁头从一端移动到另一端的距离,这个过程很快,因为它是连续的,没有寻道时间。
-
-
效率:
-
C-SCAN算法通过直接从一端移动到另一端,减少了磁头的寻道时间,提高了磁盘访问的效率。
-
这种算法特别适合于请求分布均匀的情况,因为它可以确保所有请求都能被快速处理。
-
-
公平性:
-
C-SCAN算法在处理请求时,可能会对靠近磁头起始位置的请求提供更快的服务,而对远离起始位置的请求提供较慢的服务。
-
代码实现
从提供的幻灯片内容中,我们可以提取出两个函数的代码:make_request
和 add_request
,以及一个宏定义 IN_ORDER
。以下是提取的代码和总结:
提取的代码
// 创建一个磁盘请求
static void make_request()
{struct request *req;req->sector = bh->b_blocknr << 1;add_request(major + blk_dev, req);
}
// 将请求添加到请求队列
static void add_request(struct blk_dev_struct *dev, struct request *req)
{struct request *tmp = dev->current_request;req->next = NULL;cli(); // 关中断(互斥)for (; tmp->next; tmp = tmp->next)if (IN_ORDER(tmp, req) || !IN_ORDER(tmp, tmp->next))&& IN_ORDER(req, tmp->next)) break;req->next = tmp->next; tmp->next = req; sti();
}
// 判断请求是否有序
#define IN_ORDER(s1, s2) \((s1)->dev < (s2)->dev || \((s1)->dev == (s2)->dev && (s1)->sector < (s2)->sector))
代码总结
-
make_request
函数:-
这个函数初始化一个新的磁盘请求,设置请求的扇区号
req->sector
,并将请求添加到磁盘请求队列中。 -
bh->b_blocknr << 1
:假设每个块由两个扇区组成,因此将块号左移一位来计算扇区号。
-
-
add_request
函数:-
这个函数将一个新的请求插入到磁盘请求队列中,保持队列的有序性。
-
使用
cli()
关闭中断来确保在操作请求队列时的互斥访问。 -
通过
IN_ORDER
宏判断请求是否有序,如果新请求应该插入到tmp
和tmp->next
之间,则进行插入。 -
使用
sti()
重新开启中断。
-
-
IN_ORDER
宏:-
这个宏用于判断两个请求是否有序,即是否按照设备号和扇区号的顺序排列。
-
如果第一个请求的设备号小于第二个请求的设备号,或者设备号相同但扇区号小于第二个请求的扇区号,则认为有序。
-
总结如何使用生磁盘
这张幻灯片介绍了操作系统中生磁盘(raw disk)的使用流程,以及如何通过磁盘驱动程序来管理多个进程对磁盘的访问。
-
进程获取盘块号:
-
进程首先需要获取到要访问的盘块号(block number)。
-
-
计算扇区号:
-
根据盘块号计算出对应的扇区号(sector number)。这通常涉及到将盘块号映射到磁盘的物理地址。
-
-
创建请求并加入请求队列:
-
使用计算出的扇区号创建一个磁盘请求(make req)。
-
将该请求加入到请求队列中(add_request),可能使用电梯算法(SCAN算法)来优化请求的处理顺序。
-
-
进程等待:
-
进程在发起磁盘请求后进入等待状态(sleep_on)。
-
-
磁盘中断处理:
-
当磁盘操作完成时,磁盘控制器会产生一个中断信号。
-
中断处理程序(read_intr)被触发,唤醒等待的进程。
-
-
执行磁盘请求:
-
磁盘驱动程序处理请求(do_hd_request),计算出具体的柱面(cylinder)、磁头(head)和扇区号(sector)。
-
-
端口写入:
-
使用端口写入操作(hd_out),通过outp函数将数据写入磁盘控制器的端口,完成数据的实际读写操作。
-