Linux 0.11 内核在 hd_out 之后磁盘准备数据时做什么?

问题描述 投票:0回答:1

我正在探索 Linux 0.11 源代码,特别是它如何将数据从磁盘读取到内存中。我一直在分析

hd_out
函数以及
do_hd_request
中相关的
hd.c

以下是相关代码片段:

#define CURRENT (blk_dev[MAJOR_NR].current_request)

// hd.c
void do_hd_request(void) {
    ...
    unsigned int dev = MINOR(CURRENT->dev);
    unsigned int block = CURRENT->sector;
    ...
    nsect = CURRENT->nr_sectors;
    ...
    if (CURRENT->cmd == WRITE) {
        hd_out(dev, nsect, sec, head, cyl, WIN_WRITE, &write_intr);
        // Poll status register to check if ready to write
        for (i = 0; i < 3000 && !(r = inb_p(HD_STATUS) & DRQ_STAT); i++);
        if (!r) {
            bad_rw_intr();
            goto repeat;
        }
        port_write(HD_DATA, CURRENT->buffer, 256);
    } else if (CURRENT->cmd == READ) {
        hd_out(dev, nsect, sec, head, cyl, WIN_READ, &read_intr);
    } else
        panic("unknown hd-command");
}

static void hd_out(unsigned int drive, unsigned int nsect, unsigned int sect,
                   unsigned int head, unsigned int cyl, unsigned int cmd,
                   void (*intr_addr)(void)) {
    ...
    do_hd = intr_addr;
    outb_p(hd_info[drive].ctl, HD_CMD);
    port = HD_DATA;
    outb_p(hd_info[drive].wpcom >> 2, ++port);
    outb_p(nsect, ++port);
    outb_p(sect, ++port);
    outb_p(cyl, ++port);
    outb_p(cyl >> 8, ++port);
    outb_p(0xA0 | (drive << 4) | head, ++port);
    outb(cmd, ++port);
}

根据我的理解,

hd_out
向磁盘发出命令并分配适当的中断处理程序(例如,
read_intr
write_intr
)。然后磁盘开始准备数据。我的问题是:磁盘准备数据时内核做了什么?

我假设内核应该切换到另一个进程(通过计时器中断或类似机制),但是当我调试该进程时,我注意到在

hd_out
之后,执行的下一条指令是磁盘中断处理程序(例如,
hd_interrupt
),表明磁盘已立即准备就绪。这种行为看起来很奇怪,因为我预计在磁盘准备期间会发生进程切换。

  • 在等待磁盘准备期间内核是否会切换到另一个进程?
  • 如果没有发生进程切换,内核如何确保不浪费CPU周期?

对此行为的任何澄清将不胜感激!

linux-kernel operating-system interrupt disk-io
1个回答
0
投票

它切换到不同的进程。

您缺少的是:存在一个请求队列。当进程读取或写入时,它不会直接调用

do_hd_request()
。相反,它将请求放入队列中,然后进入睡眠状态。如果队列为空,它只会调用
do_hd_request()

当磁盘操作完成时,磁盘中断会将请求标记为已完成,唤醒等待该请求的进程,然后从队列中发出下一个请求。因此,除非队列为空,否则您的请求将由中断处理程序在完成前一个请求后发出。这就是为什么从

do_hd_request()
调用
hd_interrupt

相关代码:

  • 发出请求并继续执行:
    fs/buffer.c
    寻找
    wait_for_buffer()
    ll_rw_block()
  • 将请求添加到队列:
    kernel/blk_drv/ll_rw_blk.c
    注意:对于 HDD,
    (dev->request_fn)()
    将解析为
    do_hd_request()
  • 硬盘中断:
    kernel/system_call.s:hd_interrupt
    。致电
    read_intr()
    write_intr()
  • 读/写完成处理程序:
    kernel/blk_drv/hd.c
    。再次呼叫
    do_hd_request()
    ,以及
    end_request()
  • 结束请求并唤醒进程:
    kernel/blk_drv/blk.h
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.