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),要么就保存在裸设备里.我 ...
随机推荐
- windows10 64bit 下的tensorflow 安装及demo
目前流行的深度学习库有Caffe,Keras,Theano,本文采用谷歌开源的曾用来制作AlphaGo的深度学习系统Tensorflow. 1:安装Tensorflow 最早TensorFlow只支持 ...
- JavaScript 第九章总结
Handing events 前言 这一章节主要讲了关于 events 的内容,讲了 event 的定义,以及如何用 code 来 react to events.同时,也说明了 JavaScript ...
- 雷林鹏分享:jQuery EasyUI 树形菜单 - 创建复杂树形网格
jQuery EasyUI 树形菜单 - 创建复杂树形网格 树形网格(TreeGrid)可以展示有限空间上带有多列和复杂数据电子表格.本教程将演示如何将表格数据排列在分割的网格和多行表头中,以便组织共 ...
- yarn hadoop-2.3.0 installation cluster Centos 64bits
Apache Hadoop -2.2.0 - How to Install a Three Nodes Cluster http://tonylixu.blogspot.ca/2014/02/apac ...
- CentOS6启动流程
CentOS6启动流程 1.加载BIOS的硬件信息,获取第一个启动设备 在通电之后,CentOS6会进行加电自检(Power On Self Test),这个过程主要是由BIOS完成的.在自检完毕,会 ...
- Remove Duplicates From Sorted Array leetcode java
算法描述: Given a sorted array, remove the duplicates in place such that each element appear only once a ...
- 3月26 document的练习
1.Window.document对象 一.找到元素: docunment.getElementById("id"):根据id找,最多找一个: var a =docunme ...
- node模块之path——path.join和path.resolve的区别
1.path.join([...paths]) path.join() 方法使用平台特定的分隔符把全部给定的 path 片段连接到一起,并规范化生成的路径. 长度为零的 path 片段会被忽略. 如果 ...
- HDU-2767-tarjan/Kosaraju求scc
http://acm.hdu.edu.cn/showproblem.php?pid=2767 问最少添加几条边使得图为强连通. tarjan跑一下,然后对强连通分量缩点,找下此时出度为零和入度为零的点 ...
- PAT 1005 Spell It Right
1005 Spell It Right (20 分) Given a non-negative integer N, your task is to compute the sum of all ...