Mr Dk.'s BlogMr Dk.'s Blog
  • 🦆 About Me
  • ⛏️ Technology Stack
  • 🔗 Links
  • 🗒️ About Blog
  • Algorithm
  • C++
  • Compiler
  • Cryptography
  • DevOps
  • Docker
  • Git
  • Java
  • Linux
  • MS Office
  • MySQL
  • Network
  • Operating System
  • Performance
  • PostgreSQL
  • Productivity
  • Solidity
  • Vue.js
  • Web
  • Wireless
  • 🐧 How Linux Works (notes)
  • 🐧 Linux Kernel Comments (notes)
  • 🐧 Linux Kernel Development (notes)
  • 🐤 μc/OS-II Source Code (notes)
  • ☕ Understanding the JVM (notes)
  • ⛸️ Redis Implementation (notes)
  • 🗜️ Understanding Nginx (notes)
  • ⚙️ Netty in Action (notes)
  • ☁️ Spring Microservices (notes)
  • ⚒️ The Annotated STL Sources (notes)
  • ☕ Java Development Kit 8
GitHub
  • 🦆 About Me
  • ⛏️ Technology Stack
  • 🔗 Links
  • 🗒️ About Blog
  • Algorithm
  • C++
  • Compiler
  • Cryptography
  • DevOps
  • Docker
  • Git
  • Java
  • Linux
  • MS Office
  • MySQL
  • Network
  • Operating System
  • Performance
  • PostgreSQL
  • Productivity
  • Solidity
  • Vue.js
  • Web
  • Wireless
  • 🐧 How Linux Works (notes)
  • 🐧 Linux Kernel Comments (notes)
  • 🐧 Linux Kernel Development (notes)
  • 🐤 μc/OS-II Source Code (notes)
  • ☕ Understanding the JVM (notes)
  • ⛸️ Redis Implementation (notes)
  • 🗜️ Understanding Nginx (notes)
  • ⚙️ Netty in Action (notes)
  • ☁️ Spring Microservices (notes)
  • ⚒️ The Annotated STL Sources (notes)
  • ☕ Java Development Kit 8
GitHub
  • 🐧 Linux Kernel Comments
    • Chapter 2 - 微型计算机组成结构

      • Chapter 2 - 微型计算机组成结构
    • Chapter 3 - 内核编程语言和环境

      • Chapter 3 - 内核编程语言和环境
    • Chapter 4 - 80X86 保护模式及其编程

      • Chapter 4.1-4.2 - 80X86 系统寄存器和系统指令 & 保护模式内存管理
      • Chapter 4.3 - 分段机制
      • Chapter 4.4 - 分页机制
      • Chapter 4.5 - 保护
      • Chapter 4.6 - 中断和异常处理
      • Chapter 4.7 - 任务管理
      • Chapter 4.8 - 保护模式编程初始化
      • Chapter 4.9 - 一个简单的多任务内核实例
    • Chapter 5 - Linux 内核体系结构

      • Chapter 5.1-5.2 - Linux 内核模式 & 体系结构
      • Chapter 5.3 - Linux 内核对内存的管理和使用
      • Chapter 5.4-5.6 - 中断机制 & 系统调用 & 系统时间和定时
      • Chapter 5.7-5.9 - Linux 进程控制 & 堆栈使用 & 文件系统
    • Chapter 6 - 引导启动程序 (boot)

      • Chapter 6 - 引导启动程序 (boot)
    • Chapter 7 - 初始化程序 (init)

      • Chapter 7 - 初始化程序 (init)
    • Chapter 8 - 内核代码

      • Chapter 8.1 - 内核代码总体功能
      • Chapter 8.2 - asm.s 程序
      • Chapter 8.3 - traps.c 程序
      • Chapter 8.4 - sys_call.s 程序
      • Chapter 8.5 - mktime.c 程序
      • Chapter 8.6 - sched.c 程序
      • Chapter 8.7 - signal.c 程序
      • Chapter 8.8 - exit.c 程序
      • Chapter 8.9 - fork.c 程序
      • Chapter 8.10 - sys.c 程序
    • Chapter 9 - 块设备驱动程序

      • Chapter 9.1 - 块设备驱动程序 总体功能
      • Chapter 9.2 - blk.h 文件
      • Chapter 9.3 - hd.c 程序
      • Chapter 9.4 - ll_rw_blk.c 程序
      • Chapter 9.5 - ramdisk.c 程序
    • Chapter 10 - 字符设备驱动程序

      • Chapter 10.1 - 字符设备驱动程序 总体功能
      • Chapter 10.2 - keyboard.S 程序
      • Chapter 10.3 - console.c 程序
      • Chapter 10.4 - serial.c 程序
      • Chapter 10.5 - rs_io.s 程序
      • Chapter 10.6 - tty_io.c 程序
      • Chapter 10.7 - tty_ioctl.c 程序
    • Chapter 12 - 文件系统

      • Chapter 12.1 - 文件系统 总体功能
      • Chapter 12.2 - buffer.c 程序
      • Chapter 12.3 - bitmap.c 程序
      • Chapter 12.4 - truncate.c 程序
      • Chapter 12.5 - inode.c 程序
      • Chapter 12.6 - super.c 程序
      • Chapter 12.7 - namei.c 程序
      • Chapter 12.9 - block_dev.c 程序
      • Chapter 12.10 - file_dev.c 程序
      • Chapter 12.11 - pipe.c 程序
      • Chapter 12.12 - char_dev.c 程序
      • Chapter 12.13 - read_write.c 程序
      • Chapter 12.14 - open.c 程序
      • Chapter 12.15 - exec.c 程序
      • Chapter 12.16 - stat.c 程序
      • Chapter 12.17 - fcntl.c 程序
      • Chapter 12.18 - ioctl.c 程序
      • Chapter 12.19 - select.c 程序

Chapter 9.2 - blk.h 文件

Created by : Mr Dk.

2019 / 08 / 22 14:49

Ningbo, Zhejiang, China


9.2 blk.h 文件

9.2.1 功能描述

块设备参数的头文件,定义了请求等待队列中的请求项数据结构 request。用宏语句定义了电梯搜索算法。对内核目前支持的设备,根据其各自的主设备号分别定义了对应的常数值。

9.2.2 代码注释

块设备表

每种块设备占用一项,index 即为主设备号:

#define NR_BLK_DEV 7

struct blk_dev_struct {
    void (*reuqest_fn) (void); // 设备的请求处理函数
    struct request * current_request; // 设备当前正在处理的请求
};

extern struct blk_dev_struct blk_dev[NR_BLK_DEV];

设备请求项结构体及其数组

#define NR_REQUEST 32

struct request {
    int dev; // 发出请求的设备号,-1 代表空闲
    int cmd; // READ | WRITE
    int errors; // 操作产生的错误次数
    unsigned long sector; // 起始扇区
    unsigned long nr_sectors; // 操作扇区数
    char * buffer; // 数据缓冲区
    struct task_struct * waiting; // 等待请求完成的任务
    struct buffer_head * bh; // 缓冲区头指针
    struct request * next; // 指向下一个请求项
};

// 请求项数组
extern struct request request[NR_REQUEST];

// 等待空闲请求项的进程队列头指针
// 32 个请求项全被占满时,进程在队列中排队
extern struct task_struct * wait_for_request;

数据块总数指针数组 blk_size[]

指向对应主设备号的总块数数组 hd_sizes[]。

extern int * blk_size[NR_BLK_DEV];

设备宏

#ifdef MAJOR_NR

#if (MAJOR_NR == 1)
#define DEVICE_NAME "ramdisk"
#define DEVICE_REQUEST do_rd_request // 虚拟盘请求项处理函数
#define DEVICE_NR(device) ((device) & 7) // 子设备号 0 - 7
#define DEVICE_ON(device) // 虚拟盘无需开启和关闭
#define DEVICE_OFF(device)

#elif (MAJOR_NR == 2)
#define DEVICE_NAME "floppy"
#define DEVICE_INTR do_floppy // 软盘中断处理函数
#define DEVICE_REQUEST do_fd_request // 软盘请求项处理函数
#define DEVICE_NR(device) ((device) & 3) // 子设备号 0 - 3
#define DEVICE_ON(device) floppy_on(DEVICE_NR(device)) // 开启设备宏
#define DEVICE_OFF(device) floppy_off(DEVICE_NR(device)) // 关闭设备宏

#elif (MAJOR_NR == 3)
#define DEVICE_NAME "harddisk"
#define DEVICE_INTR do_hd // 硬盘中断处理函数
#define DEVICE_TIMEOUT hd_timeout // 硬盘超时值
#define DEVICE_REQUEST do_hd_request // 硬盘请求项处理函数
#define DEVICE_NR(device) (MINOR(device) / 5) // 设备号 0 - 1
#define DEVICE_ON(device) // 硬盘一开机总是运转着
#define DEVICE_OFF(device)

#elif
#error "unknown blk device"

#endif

当前请求项的宏 CURRENT

#define CURRENT (blk_dev[MAJOR_NR].current_request) // 主设备的当前请求指针
#define CURRENT_DEV DEVICE_NR(CURRENT->dev) // 当前请求项的设备号

结束请求处理函数 end_request()

首先是一个解锁缓冲块的子函数:

这个缓冲块具体指的是什么还没太明白。请求结构里又有一个数据缓冲块的指针,又有一个缓冲区头指针,不知道有什么区别。

extern inline void unlock_buffer(struct buffer_head * bh)
{
    if (!bh->b_lock)
        printk(DEVICE_NAME ": free buffer being unlocked\n");
    bh->b_block = 0;
    wake_up(&bh->b_wait);
}
  • 首先关闭指定的块设备
  • 检查此次读写缓冲区是否有效:有效则设置缓冲区更新标志,解锁该缓冲区;否则显示相关的 I/O 出错信息
  • 唤醒等待该请求项的进程
  • 唤醒等待空闲请求项的进程
  • 释放并从链表中清除本请求项
  • 处理下一个请求项
extern inline void end_request(int uptodate)
{
    DEVICE_OFF(CURRENT->dev); // 关闭设备
    if (CURRENT->bh) {
        CURRENT->bh->b_uptodate = uptodate; // 设置缓冲区更新标志
        unlock_buffer(CURRENT->bh); // 解锁缓冲区
    }
    if (!uptodate) {
        // 出错
        printk(DEVICE_NAME "I/O error\n\r");
        printk("dev %04x, block %d\n\r", CURRENT->dev, CURRENT->bh->b_blocknr);
    }
    wake_up(&CURRENT->waiting); // 唤醒等待该请求项的进程
    wake_up(&wait_for_request); // 唤醒等待空闲请求项的进程
    CURRENT->dev = -1; // 释放该请求项
    CURRENT = CURRENT->next; // 指向下一个请求项
}

请求项初始化宏 INIT_REQUEST

几个块设备驱动程序的开始处,对请求项的初始化操作类似。因此定义一个统一的初始化宏,并对当前请求项进行一些有效性判断:

  • 若当前请求项为空,则设备已经没有需要处理的请求项了,扫尾后退出函数
  • 主设备号 ≠ 驱动程序定义的主设备号,说明请求项队列错乱,内核 panic
  • 若请求项中使用的缓冲块没有被锁定,说明 kernel 也有问题,panic
#define INIT_REQUEST \
repeat: \
    if (!CURRENT) { \ // 当前请求项为空
        CLEAR_DEVICE_INTR \
        CLEAR_DEVICE_TIMEOUT \
        return; \
    } \
    if (MAJOR(CURRENT->dev) != MAJOR_NR)\ // 主设备号不对
        panic(DEVICE_NAME ": request list destroyed"); \
    if (CURRENT->bh) { \
        if (!CURRENT->bh->b_lock) \ // 缓冲区未锁定
            panic(DEVICE_NAME ": block not locked"); \
    }
#endif
Edit this page on GitHub
Prev
Chapter 9.1 - 块设备驱动程序 总体功能
Next
Chapter 9.3 - hd.c 程序