系统调用-read
入口
read_write.c/sys_read()
函数签名
asmlinkage ssize_t sys_write(unsigned int fd, const char __user * buf, size_t count)
调用
-
tmp = getname(filename) 将文件字符串从用户态转换到内核态
-
file_table.c/fget_light(fd, fput_needed) 根据fd获取file
- 从current->files->fd[fd]中获取sys_open打开的file
-
read_write.c/file_pos_read(file) 获取file的读取位置f_ops
-
read_write.c/vfs_read(file, buf, count, pos) 通过vfs读取文件内容到缓存中
- 判断权限,如open的时候是否指定可读权限,以及file对应的文件系统是否有对应的read方法
- 调用file->f_op->read/file->f_op->aio_read方法
- 调用filemap.c/generic_file_read 这里的怎么到文件系统的,可以见下一个章节file->op
- 创建iovec向量(这个是用来批量文件操作)和kiocb(这个具体啥用不懂) 通过buff和count
- filemap.c/__generic_file_aio_read 这里做了一些参数转换
- do_generic_file_read
- do_generic_mapping_read 核心方法,支持page_cache缓存读取和实际磁盘的读取,接下来主要分析page_cache miss读取实际磁盘加载到page_cache,以及page_cache命中2种逻辑,中间还有缓存是否dirty等一系列逻辑
- 通过*ppos >> PAGE_CACHE_SHIFT 计算block的索引数, 即磁盘block大小(等于一个page页大小),
- 通过req_size = (desc->count + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT 计算需要请求的block数
- 接下来通过for循环读取磁盘文件内容
-
先判断要读取的index是否大于文件最大block数
-
预读处理readahead.c/page_cache_readahead,这块不是很懂,以后在补充
-
filemap.c/find_get_page(mapping, index) 从page_cache中获取缓存,基于索引从基数树中查询缓存
- radix-tree.c/radix_tree_lookup(&mapping->page_tree, offset) 在基树上查询是否有记录
-
第一种情况,cache miss,会先调整预读参数 readahead.c/handle_ra_miss,然后实际读取文件
- pagemap.c/page_cache_alloc_cold(address_mapping) 先分配page cache页,注意此时还没有填充磁盘内存
- pagemap.c/page_cache_alloc_cold(address_mapping) 先分配page cache页,注意此时还没有填充磁盘内存
-
- do_generic_mapping_read 核心方法,支持page_cache缓存读取和实际磁盘的读取,接下来主要分析page_cache miss读取实际磁盘加载到page_cache,以及page_cache命中2种逻辑,中间还有缓存是否dirty等一系列逻辑
- do_generic_file_read
- 调用filemap.c/generic_file_read 这里的怎么到文件系统的,可以见下一个章节file->op