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.5 - ramdisk.c 程序

Created by : Mr Dk.

2019 / 08 / 23 21:32

Ningbo, Zhejiang, China


9.5 ramdisk.c 程序

9.5.1 功能描述

虚拟盘:利用物理内存来模拟实际磁盘存储数据;目的:提高对磁盘数据的读写速度;缺点:系统关闭或崩溃时,虚拟盘中的数据将会丢失。因此虚拟盘中通常存放一些系统命令等常用工具程序或临时数据。编译时,如果开启了 RAMDISK 选项,那么虚拟盘的位置会在内核初始化时确定,位于内核高速缓冲区和主内存区之间:

9-6

对于虚拟盘的读写访问操作原则上与普通磁盘的操作相同,也按照块设备的访问方式进行操作。但由于在实现上不牵扯到与外部控制器的同步操作,因此不需要硬盘中的中断机制,只需要实现内存数据的拷贝即可。

rd_init() 函数在内核初始化时被调用,用于确定虚拟盘在物理内存中的具体位置和大小。

do_rd_request() 是虚拟盘设备的请求处理函数。

rd_load() 是虚拟盘根文件系统的加载函数,在内核初始化阶段,尝试从引导盘上把根文件系统加载到虚拟盘中。起始磁盘块:第 256 块。

在使用普通方法从别的磁盘设备上加载根文件系统之前,系统首先执行 rd_load() 函数,尝试从第 257 块中读取根文件系统的 超级块:

  • 如果成功,就把根文件映像文件读到内存虚拟盘中,并设置根文件系统设备为虚拟盘设备
  • 否则退出该函数,从别的设备上加载根文件系统

系统尝试检测从第 256 次磁盘块开始,是否存在一个根文件系统,判断第 257 磁盘块中是否是一个根文件系统的有效超级块:

9-8

9.5.2 代码注释

虚拟盘在内存中的起始位置

会在初始化函数 rd_init() 中确定。该函数会在内核初始化时被调用。

char *rd_start; // 虚拟盘在内存中的开始地址
int rd_length = 0; // 虚拟盘所占内存大小 (字节)

虚拟盘的请求处理函数 do_rd_request()

在请求项加入虚拟盘设备的请求链表之后,调用该函数对请求项进行处理。首先计算:

  • 指定的 起始扇区 对应 虚拟盘所处内存的起始位置
  • 要求的 扇区数 对应 字节长度值

然后根据读/写命令进行操作:请求项所指向的缓冲区 和 虚拟盘设备对应的内存区 之间的数据复制。复制完成之后,直接调用 end_request() 销毁本次请求,然后跳转到函数开始处,处理下一个请求项 (因为不需要通过中断机制与设备控制器进行同步)。

void do_rd_request(void)
{
    int len;
    char *addr;
    
    // 检测请求项合法性
    // repeat:
    INIT_REQUEST; // 当前请求项为空,直接退出
    // 计算当前处理扇区的内存地址,和处理扇区的字节长度
    addr = rd_start + (CURRENT->sector << 9); // sector * 512B
    len = CURRENT->nr_sectors << 9; // sector * 512B
    
    if ((MINOR(CURRENT->dev) != 1) || (addr+len > rd_start+rd_length)) {
        // 子设备号不为 1 || 对应内存位置大于虚拟盘末尾
        end_request(0); // 直接结束请求
        goto repeat; // 处理下一个请求项
    }
    
    // 进行实际的读写操作
    if (CURRENT->cmd == WRITE) {
        (void) memcpy(addr, CURRENT->buffer, len); // 缓冲区 -> 虚拟盘
    } else if (CURRENT->cmd == READ) {
        (void) memcpy(CURRENT->buffer, addr, len); // 虚拟盘 -> 缓冲区
    } else
        panic("unknown ramdisk-command");
    
    // 请求项处理成功
    // 后处理
    end_request(1); // 释放请求项,指向下一个请求项
    goto repeat; // 处理下一个请求
}

虚拟盘初始化函数 rd_init()

设置虚拟盘的请求项处理函数,确定虚拟盘在物理内存中的起始地址和长度,将整个虚拟盘区清零,最终返回盘区长度。

long rd_init(long mem_start, int length)
{
    int i;
    char *cp;
    
    blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; // do_rd_request()
    
    rd_start = (char *) mem_start;
    rd_length = length;
    
    cp = rd_start;
    for (i = 0; i < length; i++)
        *cp++ = '\0';
    return (length);
}

加载根文件系统到虚拟盘中 rd_load()

根文件系统映像 位于第 256 磁盘块开始处。

void rd_load(void)
{
    struct buffer_head *bh;
    struct super_block s; // 文件系统 super block
    int block = 256; // 根文件系统映像磁盘块号
    int i = 1;
    int nblocks; // 文件系统盘块数
    char *cp;
    
    // 检查虚拟盘的有效性和完整性
    if (!rd_length)
        // 虚拟盘长度为 0
        return;
    printk("Ram disk: %d bytes, starting at 0x%x\n", rd_length, (int) rd_start);
    if (MAJOR(ROOT_DEV) != 2)
        // 根文件设备不是软盘
        return;
    
    // 读取根文件系统的基本参数
    bh = breada(ROOT_DEV, block+1, block, block+2, -1); // 读入缓冲区
    if (!bh) {
        // 读取失败
        printk("Disk error while looking for ramdisk!\n");
        return;
    }
    *((struct d_super_block *) &s) = *((struct d_super_block *) bh->b_data); // 从缓冲区中拷贝文件系统超级块
    brelse(bh); // 释放缓冲区
    if (s.s_magic != SUPER_MAGIC)
        // 磁盘中没有根文件系统映像文件
        return;
    
    // 尝试将整个根文件系统读入内存虚拟盘中
    // 超级块结构体中的 s_nzones 字段保存了文件系统的总逻辑块数
    // 一个逻辑块中含有的数据块数由 s_log_zone_size 指定
    // 文件系统中的数据块总数 = s_nzones * 2^s_log_zone_size
    nblocks = s.s_nzones << s.s_log_zone_size;
    if (nblocks > (rd_length >> BLOCK_SIZE_BITS)) {
        // 虚拟盘无法容纳文件系统数据块总数
        // 不能执行加载操作
        printk("Ram disk image too big! (%d blocks, %d avail)\n", nblocks, rd_length >> BLOCK_SIZE_BITS);
        return;
    }
    
    printk("Loading %d bytes into ram disk... 0000k", nblocks << BLOCK_SIZE_BITS);
    cp = rd_start; // 指向虚拟盘开始处
    while (nblocks) {
        // 将一个块读取到缓冲区中
        if (nblocks > 2)
            bh = breada(ROOT_DEV, block, block+1, block+2, -1);
        else
            bh = bread(ROOT_DEV, block);
        if (!bh) {
            printk("I/O error on block %d, aborting load\n", block);
            return;
        }
        (void) memcpy(cp, bh->b_data, BLOCK_SIZE); // 缓冲区 -> 虚拟盘
        brelse(bh); // 释放缓冲区
        
        printk("\010\010\010\010\010%4dk", i);
        cp += BLOCK_SIZE; // 虚拟盘当前的空白位置
        block++; // 读取的磁盘块号
        nblocks--; // 剩余要读取的磁盘块数
        i++; // 当前复制的块数
    }
    
    // 根文件系统加载完毕
    printk("\010\010\010\010\010done \n");
    ROOT_DEV = 0x0101; // 根文件系统设备号修改为虚拟盘设备号
}
Edit this page on GitHub
Prev
Chapter 9.4 - ll_rw_blk.c 程序