深入了解Linux read源码不仅可以帮助我们更好地理解操作系统的运行机制,还能提高我们在开发和调试中的效率
本文将结合Linux 0.11版本的内核源码,详细解析read操作的实现过程
一、Linux Read操作概述 在Linux系统中,read操作是从用户空间发起的,通过系统调用接口进入内核空间执行
具体来说,当我们在用户空间中调用read函数时,编译器会将其编译成软中断`int 0x80`,通过中断处理机制进入内核空间,并找到系统调用表里的sys_read函数执行
sys_read函数的定义位于`fs/read_write.c`文件中,它的作用是从指定的文件描述符(file descriptor,简称fd)中读取数据到用户提供的缓冲区(buffer)中
这个函数的原型如下: asmlinkage ssize_tsys_read(unsigned int fd,char __user buf, size_t count); 其中,fd是文件描述符,buf是存放读取数据的缓冲区,count是期望读取的数据大小
二、sys_read函数详解 sys_read函数的实现过程相当复杂,涉及多个关键步骤
首先,它会通过文件描述符获取文件指针,然后检查参数的有效性,接着执行实际的读取操作,并更新文件读写位置,最后释放文件指针并返回读取的数据大小
1. 获取文件指针 sys_read函数首先通过文件描述符获取文件指针
这个过程是通过`fget_light`函数实现的,它会检查当前进程的`task_struct`结构中的`files`指针,然后从`files`结构体的`fd`数组上获取对应的`file`结构体
struct filefile; int fput_needed; file = fget_light(fd, &fput_needed); 2. 检查参数有效性 在获取到文件指针后,sys_read函数会检查参数的有效性
这包括检查文件描述符是否超出打开文件的最大数量、读取数据的大小是否为负数以及文件指针是否为空
if (fd >=NR_OPEN || count < 0|| !(file = current->filp【fd】)) return -EINVAL; if (!count) return 0; 3. 验证用户内存区域 为了确保用户提供的缓冲区是合法的,sys_read函数会调用`verify_area`函数来验证用户传入的内存区域是否可写
这是内核安全性的一部分,以防止用户空间非法访问内核空间
verify_area(buf,count); 4. 执行读取操作 在参数检查和内存验证通过后,sys_read函数会调用`vfs_read`函数执行实际的读取操作
vfs_read是虚拟文件系统(Virtual File System,简称VFS)层提供的接口,它支持不同类型的文件系统
loff_t pos = file_pos_read(file); ssize_t ret = vfs_read(file, buf, count, &pos); file_pos_write(file,pos); vfs_read函数会根据文件的类型(如普通文件、管道、字符设备等)调用相应的读取函数
例如,对于普通文件,它会调用`file->f_op->read`或`do_sync_read`函数来读取数据
5. 更新文件读写位置和释放文件指针 读取操作完成后,sys_read函数会更新文件的读写位置,并释放文件指针
这是通过`file_pos_write`和`fput_light`函数实现的
file_pos_write(file,pos); fput_light(file, fput_needed); 6. 返回读取的数据大小 最后,sys_read函数会返回读取的数据大小
如果读取过程中出现错误,它会返回相应的错误码
return ret; 三、Linux 0.11中的Read实现 在Linux 0.11版本中,read操作的实现与现代版本有所不同,但基本原理是相似的
Linux 0.11使用的是MINIX文件系统,它包含引导块、超级块、i-node位图、逻辑块位图、i节点与数据区等组成部分
1. 文件系统结构 - 引导块:计算机加电启动时由BIOS自动读入的执行代码和数据,作为引导设备
- 超级块:存储文件系统信息,包括文件系统类型、块大小、块数量、i节点数量等
- i节点位图:记录文件系统中i节点(Inode)的分配状态
逻辑块位图:记录文件系统中数据块的分配状态
- i节点:存放文件或目录的元数据,如文件宿主的ID、文件所属组ID、文件权限、文件大小、文件创建时间等
2. 文件读取流程 在Linux 0.11中,read操作的实现涉及到多个函数的调用,包括`sys_read`、`file_read`、`bread`和`ll_rw_block`等
- sys_read:系统调用入口,负责参数检查、内存验证和调用vfs_read函数
- file_read:从底层读取对应文件的对应数据,首先将文件偏移转换为硬盘块号,然后读取数据块到缓冲区,最后将数据复制到用户提供的缓冲区中
- bread:从缓存或硬盘中读取数据块
如果数据块已经在缓存中并且是最新的,则直接返回;否则,调用`ll_rw_block`函数从硬盘读取数据
- ll_rw_block:负责将读取请求发送到硬