Linux3.10.0块IO子系统流程(1)-- 上层提交请求
void submit_bio(int rw, struct bio *bio)
{
bio->bi_rw |= rw; //记录读写方式
/*
* 执行有数据传输的读写或屏障请求统计,暂不关心
*/
if (bio_has_data(bio)) {
unsigned int count;
if (unlikely(rw & REQ_WRITE_SAME))
count = bdev_logical_block_size(bio->bi_bdev) >> ;
else
count = bio_sectors(bio);
if (rw & WRITE) {
count_vm_events(PGPGOUT, count);
} else {
task_io_account_read(bio->bi_size);
count_vm_events(PGPGIN, count);
}
if (unlikely(block_dump)) {
char b[BDEVNAME_SIZE];
printk(KERN_DEBUG "%s(%d): %s block %Lu on %s (%u sectors)\n",
current->comm, task_pid_nr(current),
(rw & WRITE) ? "WRITE" : "READ",
(unsigned long long)bio->bi_sector,
bdevname(bio->bi_bdev, b),
count);
}
}
//执行真实的IO处理
generic_make_request(bio);
}
void generic_make_request(struct bio *bio)
{
struct bio_list bio_list_on_stack;
if (!generic_make_request_checks(bio))
return; if (current->bio_list) {
bio_list_add(current->bio_list, bio);
return;
} BUG_ON(bio->bi_next);
bio_list_init(&bio_list_on_stack);
current->bio_list = &bio_list_on_stack;
do {
struct request_queue *q = bdev_get_queue(bio->bi_bdev); //获取bio对应的请求队列
q->make_request_fn(q, bio); //调用请求队列的回调函数来处理IO
bio = bio_list_pop(current->bio_list);
} while (bio);
current->bio_list = NULL; /* deactivate */
}
- generic_make_request_checks
- 判断make_request是否处于活动状态。如果current->bio_list不为NULL,则表明当前进程已经有generic_make_request在执行,这时候传进来的bio都将链接到当前进程等待处理的bio链表尾部
- 设置current->bio_list表明当前的generic_make_request为活动状态,让后来的bio有机会插入等待链表
- 处理bio。这里的bio可能是传入的bio,也可能是当前进程待处理bio链表中的bio。如果是前者,上层保证了其bi_next必然为NULL;如果是后者,则在将bio从链表中脱离的时候,已经设置了bi_next为NULL
- 调用make_request_fn回调处理bio
- 检查当前进程的等待链表中是否还有bio,如果有,跳到第三步
- 至此,generic_make_request的“本轮执行周期”已经完毕,清零current->bio_list,使得generic_make_request处于“非活动”状态
static noinline_for_stack bool
generic_make_request_checks(struct bio *bio)
{
struct request_queue *q;
int nr_sectors = bio_sectors(bio);
int err = -EIO;
char b[BDEVNAME_SIZE];
struct hd_struct *part; might_sleep(); // 检查bio的扇区有没有超过块设备的扇区数
if (bio_check_eod(bio, nr_sectors))
goto end_io; // 检测块设备的请求队列是否为空
q = bdev_get_queue(bio->bi_bdev);
if (unlikely(!q)) {
printk(KERN_ERR
"generic_make_request: Trying to access "
"nonexistent block-device %s (%Lu)\n",
bdevname(bio->bi_bdev, b),
(long long) bio->bi_sector);
goto end_io;
} // 检测请求的扇区长度是否超过物理限制
if (likely(bio_is_rw(bio) &&
nr_sectors > queue_max_hw_sectors(q))) {
printk(KERN_ERR "bio too big device %s (%u > %u)\n",
bdevname(bio->bi_bdev, b),
bio_sectors(bio),
queue_max_hw_sectors(q));
goto end_io;
} part = bio->bi_bdev->bd_part;
if (should_fail_request(part, bio->bi_size) ||
should_fail_request(&part_to_disk(part)->part0,
bio->bi_size))
goto end_io; /*
* If this device has partitions, remap block n of partition p to block n+start(p) of the disk.
* 如果请求的块设备可能代表一个分区,这里重新映射到所在的磁盘设备
*/
blk_partition_remap(bio); if (bio_check_eod(bio, nr_sectors))
goto end_io; /*
* Filter flush bio's early so that make_request based
* drivers without flush support don't have to worry
* about them.
*/
if ((bio->bi_rw & (REQ_FLUSH | REQ_FUA)) && !q->flush_flags) {
bio->bi_rw &= ~(REQ_FLUSH | REQ_FUA);
if (!nr_sectors) {
err = ;
goto end_io;
}
} // 检查设备对DISCARD命令的支持
if ((bio->bi_rw & REQ_DISCARD) &&
(!blk_queue_discard(q) ||
((bio->bi_rw & REQ_SECURE) && !blk_queue_secdiscard(q)))) {
err = -EOPNOTSUPP;
goto end_io;
} if (bio->bi_rw & REQ_WRITE_SAME && !bdev_write_same(bio->bi_bdev)) {
err = -EOPNOTSUPP;
goto end_io;
} /*
* Various block parts want %current->io_context and lazy ioc
* allocation ends up trading a lot of pain for a small amount of
* memory. Just allocate it upfront. This may fail and block
* layer knows how to live with it.
*/
create_io_context(GFP_ATOMIC, q->node); if (blk_throtl_bio(q, bio))
return false; /* throttled, will be resubmitted later */ trace_block_bio_queue(q, bio);
return true; end_io:
bio_endio(bio, err);
return false;
}
generic_make_request_checks
Linux3.10.0块IO子系统流程(1)-- 上层提交请求的更多相关文章
- Linux3.10.0块IO子系统流程(0)-- 块IO子系统概述
前言:这个系列主要是记录自己学习Linux块IO子系统的过程,其中代码分析皆基于Linux3.10.0版本,如有描述错误或不妥之处,敬请指出! 参考书籍:存储技术原理分析--基于Linux 2.6内核 ...
- Linux3.10.0块IO子系统流程(7)-- 请求处理完成
和提交请求相反,完成请求的过程是从低层驱动开始的.请求处理完成分为两个部分:上半部和下半部.开始时,请求处理完成总是处在中断上下文,在这里的主要任务是将已完成的请求放到某个队列中,然后引发软终端让中断 ...
- Linux3.10.0块IO子系统流程(4)-- 为请求构造SCSI命令
首先来看scsi_prep_fn int scsi_prep_fn(struct request_queue *q, struct request *req) { struct scsi_device ...
- Linux3.10.0块IO子系统流程(3)-- SCSI策略例程
很长时间以来,Linux块设备使用了一种称为“蓄流/泄流”(plugging/unplugging)的技术来改进吞吐率.简单而言,这种工作方式类似浴盆排水系统的塞子.当IO被提交时,它被储存在一个队列 ...
- Linux3.10.0块IO子系统流程(2)-- 构造、排序、合并请求
Linux块设备可以分为三类.分别针对顺序访问物理设备.随机访问物理设备和逻辑设备(即“栈式设备”) 类型 make_request_fn request_fn 备注 SCSI 设备等 从bio构 ...
- Linux3.10.0块IO子系统流程(6)-- 派发SCSI命令到低层驱动
在SCSI策略例程中最后调用scsi_dispatch_cmd将SCSI命令描述符派发给低层驱动进行处理 /** * scsi_dispatch_command - Dispatch a comman ...
- Linux3.10.0块IO子系统流程(5)-- 为SCSI命令准备聚散列表
SCSI数据缓冲区组织成聚散列表的形式.Linux内核中表示聚散列表的基本数据结构是scatterlist,虽然名字中有list,但它只对应一个内存缓冲区,聚散列表就是多个scatterlist的组合 ...
- DPA 9.1.85 升级到DPA 10.0.352流程
SolarWinds DPA的升级其实是一件非常简单的事情,这里介绍一下从DPA 9.1.95升级到 DPA 10.0.352版本的流程.为什么要升级呢? DPA给用户发的邮件已经写的非常清楚了(如下 ...
- 【转】linux IO子系统和文件系统读写流程
原文地址:linux IO子系统和文件系统读写流程 我们含有分析的,是基于2.6.32及其后的内核. 我们在linux上总是要保存数据,数据要么保存在文件系统里(如ext3),要么就保存在裸设备里.我 ...
随机推荐
- 动态规划-填格子问题 Domino and Tromino Tiling
2018-09-01 22:38:19 问题描述: 问题求解: 本题如果是第一看到,应该还是非常棘手的,基本没有什么思路. 不妨先从一种简化的版本来考虑.如果仅有一种砖块,那么,填充的方式如下.
- Ubuntu16.04安装8821CE 无线网卡无驱动
已解决 参考链接:https://unix.stackexchange.com/question ... -mint-18-2 内容 Worked solution (Requirements: ke ...
- gitignore有时候为啥过滤不了文件或目录
一.问题介绍 使用Git过程中,有时候我们想过滤项目中的部分文件,在.gitignore中加入该文件名称或该文件所在目录的名称,比如我们的项目日志文件(.log文件) 但是有时候发现不管用.不好使. ...
- LeetCode--437--路径总和3
问题描述: 给定一个二叉树,它的每个结点都存放着一个整数值. 找出路径和等于给定数值的路径总数. 路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点). 二 ...
- windows系统文件和linux系统文件
windows系统文件和linux系统文件 1.单用户操作系统和多用户操作系统 单用户操作系统:指一台计算机在同一时间 只能由一个用户 使用,一个用户独自享用系统的全部硬件和软件资源 Windows ...
- PGAdmin 4使用笔记
1. import 默认username为postgres psql -U username -h localhost -d databasename -f "file address&qu ...
- 5月21 练习AJAX的查看详细及批量删除
老师讲过之后的复习: 显示数据的代码部分: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" &q ...
- 【其他】【服务器】【2】把jar包做成服务,在Service中管理
三个文件:service_install.xml,service_install.exe,install-service.bat: 和xx.jar放在同一个目录下 service_install.xm ...
- 【微信公众号开发】【10】JSJDK相关
前言: 1,优点:官方提供的,会调用后还算使用方便,不用费劲了解各个原生组件 缺点:使用上有限制(如:上传文件有大小限制),很容易踩坑,部分安卓手机及电脑端不支持pjax 总结:上手容易,坑很多 2, ...
- 使用vue-router设置每个页面的title
进入 router 文件夹底下的index.js文件 首先引入: import Vue from 'vue' import Router from 'vue-router' 然后在路由里面配置每个路由 ...