Repository navigation
Expand file tree
/
Copy pathlinuxiopath
More file actions
106 lines (87 loc) · 3.1 KB
/
Copy pathlinuxiopath
File metadata and controls
106 lines (87 loc) · 3.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
Linux内核中的文件系统I/O路径涉及多个层次和子系统,包括VFS(虚拟文件系统)、具体文件系统实现、块设备层等。以下是文件系统I/O路径的主要步骤和代码解释:
### 1. 用户空间到内核空间的系统调用
用户程序通过系统调用(如`read()`、`write()`)发起I/O请求,触发从用户空间到内核空间的切换。
```c
SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
{
return ksys_read(fd, buf, count);
}
```
### 2. VFS层处理
VFS层提供统一的文件操作接口,`ksys_read()`调用`vfs_read()`,后者通过文件描述符找到对应的`file`结构,并调用文件操作函数。
```c
ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
{
if (!(file->f_mode & FMODE_READ))
return -EBADF;
if (!file->f_op->read)
return -EINVAL;
return file->f_op->read(file, buf, count, pos);
}
```
### 3. 具体文件系统实现
VFS调用具体文件系统的`read`方法,如Ext4的`ext4_file_read_iter()`。
```c
const struct file_operations ext4_file_operations = {
.read_iter = ext4_file_read_iter,
.write_iter = ext4_file_write_iter,
// 其他操作
};
```
### 4. 页缓存层
文件系统通常通过页缓存读取数据,`ext4_file_read_iter()`调用`generic_file_read_iter()`,后者检查页缓存是否存在所需数据。
```c
ssize_t generic_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
{
if (iocb->ki_flags & IOCB_DIRECT)
return generic_file_direct_read(iocb, iter);
return generic_file_buffered_read(iocb, iter);
}
```
### 5. 块设备层
如果数据不在页缓存中,文件系统通过`submit_bio()`向块设备层提交I/O请求。
```c
void submit_bio(struct bio *bio)
{
bio->bi_next = NULL;
bio->bi_status = BLK_STS_OK;
generic_make_request(bio);
}
```
### 6. I/O调度层
块设备层将请求交给I/O调度器(如CFQ、Deadline),调度器对请求进行排序和合并,优化性能。
```c
void blk_mq_sched_insert_requests(struct blk_mq_hw_ctx *hctx,
struct blk_mq_ctx *ctx,
struct list_head *list, bool run_queue)
{
// 调度请求
}
```
### 7. 设备驱动层
调度后的请求通过设备驱动发送到硬件设备,如SCSI或NVMe驱动。
```c
static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
const struct blk_mq_queue_data *bd)
{
// 处理NVMe请求
}
```
### 8. 硬件设备执行
硬件设备执行I/O操作,完成后通过中断通知CPU,驱动处理中断并完成请求。
```c
irqreturn_t nvme_irq(int irq, void *data)
{
// 处理中断
}
```
### 9. 完成回调
I/O完成后,内核调用回调函数通知上层,最终将数据返回给用户空间。
```c
void blk_mq_end_request(struct request *rq, blk_status_t error)
{
// 完成请求
}
```
### 总结
Linux内核的文件系统I/O路径从用户空间系统调用开始,经过VFS、具体文件系统、页缓存、块设备层、I/O调度、设备驱动,最终由硬件设备执行。每个层次都有特定的职责,确保I/O操作高效完成。