参考
Product Documentation Red Hat Enterprise Linux7 7.2 发行注记 第 14 章 存储
blk_mq
数据缓冲区转换成prp或者sg列表
用户态分配的内存使用blk_rq_map_user,内核态分配的内存使用blk_rq_map_kern,
//xilinx petalinux-v2018.2
blk_rq_map_user
对比来看,
//xilinx petalinux-v2018.2
blk_rq_map_kern
bio_copy_kern //数据buf地址不对齐,硬件能力不支持,该分支应该很少进入,copy会带来性能降低
//类似于bounce buffer回弹缓冲区
bio_map_kern
bio_kmalloc //分配一个bio
bio_add_pc_page //把page循环加入bio
通过上面的操作把request的内存记录到bio中,通过blk_rq_map_sg,形成struct scatterlist *sg,prp或者sg列表是通过nvme_setup_prps基于struct scatterlist *sg构造的。
IO请求如何下发到SSD
创建队列的时候注册blk_mq_ops,
static const struct blk_mq_ops nvme_mq_admin_ops = {
.queue_rq= nvme_queue_rq,
.complete= nvme_pci_complete_rq,
.init_hctx= nvme_admin_init_hctx,
.exit_hctx = nvme_admin_exit_hctx,
.init_request= nvme_init_request,
.timeout= nvme_timeout,
};
static const struct blk_mq_ops nvme_mq_ops = {
.queue_rq= nvme_queue_rq,
.complete= nvme_pci_complete_rq,
.init_hctx= nvme_init_hctx,
.init_request= nvme_init_request,
.map_queues= nvme_pci_map_queues,
.timeout= nvme_timeout,
.poll= nvme_poll,
};
块设备层通过blk_execute_rq或blk_execute_rq_nowait把请求加入队列,然后下发到硬件,
//xilinx petalinux-v2018.2
nvme_queue_rq
nvme_setup_cmd
nvme_init_iod
nvme_map_data
blk_rq_map_sg
dma_map_sg_attrs
nvme_setup_prps
blk_mq_start_request
__nvme_submit_cmd
nvme_process_cq
legacy blk
传统的块设备只有一个队列,通过make_request分发io,内核在bio这块变动太多了,
#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,4,0)
#define bio_op(bio) ((bio)->bi_rw & REQ_OP_MASK)
#define bio_opf(bio) ((bio)->bi_rw)
#else
#define REQ_FLUSH REQ_PREFLUSH
#define bio_opf(bio) ((bio)->bi_opf)
#endif
验证
写一个测试脚本,
root@t2080rdb:~# cat test.sh
#!/bin/sh
echo "test read"
nvmeqe_benchmark -r /dev/nvme0n1 -p 0xe2000000 -s 0 -l 0x100000 -c 128 &
nvmeqe_benchmark -r /dev/nvme0n1 -p 0xe2100000 -s 0 -l 0x100000 -c 128 &
nvmeqe_benchmark -r /dev/nvme0n1 -p 0xe2200000 -s 0 -l 0x100000 -c 128 &
nvmeqe_benchmark -r /dev/nvme0n1 -p 0xe2300000 -s 0 -l 0x100000 -c 128
测试结果,对比测试前后的中断统计,内核把任务平均分给了各个CPU,
root@t2080rdb:~# cat /proc/interrupts | grep nvme0
58: 0 0 403 0 0 0 0 0 fsl-msi-263 15 Edge nvme0q0, nvme0q1
59: 0 0 0 109 0 0 0 0 fsl-msi-224 16 Edge nvme0q2
60: 0 0 0 0 118 0 0 0 fsl-msi-225 17 Edge nvme0q3
61: 0 0 0 0 0 755 0 0 fsl-msi-226 18 Edge nvme0q4
62: 0 0 0 0 0 0 206 0 fsl-msi-227 19 Edge nvme0q5
63: 0 0 0 0 0 0 0 439 fsl-msi-228 20 Edge nvme0q6
64: 1038 0 0 0 0 0 0 0 fsl-msi-229 21 Edge nvme0q7
65: 0 353 0 0 0 0 0 0 fsl-msi-230 22 Edge nvme0q8
root@t2080rdb:~# ./test.sh
test read
speed: 306.95MB/s, cost times: 417ms
speed: 306.22MB/s, cost times: 418ms
speed: 305.49MB/s, cost times: 419ms
speed: 305.49MB/s, cost times: 419ms
root@t2080rdb:~# cat /proc/interrupts | grep nvme0
58: 0 0 461 0 0 0 0 0 fsl-msi-263 15 Edge nvme0q0, nvme0q1
59: 0 0 0 142 0 0 0 0 fsl-msi-224 16 Edge nvme0q2
60: 0 0 0 0 243 0 0 0 fsl-msi-225 17 Edge nvme0q3
61: 0 0 0 0 0 938 0 0 fsl-msi-226 18 Edge nvme0q4
62: 0 0 0 0 0 0 260 0 fsl-msi-227 19 Edge nvme0q5
63: 0 0 0 0 0 0 0 471 fsl-msi-228 20 Edge nvme0q6
64: 1092 0 0 0 0 0 0 0 fsl-msi-229 21 Edge nvme0q7
65: 0 385 0 0 0 0 0 0 fsl-msi-230 22 Edge nvme0q8