Linux内核是如何将软硬件结合起来的呢?这里我们将一起探究内核与周围硬件主要是文件IO和硬件设备之间的关系,来解释这个问题。处理器与周围设备的通信依赖于一系列的电路电线,总线就是具有类似功能的电线,设备与处理器通信主要是通过地址总线,数据总线,控制总线来实现,这里在学习单片机原理的时候也提到过,这里对系统的基本结构就不多说了,觉得更新快,不好讲解,也没什么好总结的,大家看看相关书籍就行。

了解到设备可以当做文件系统中的文件来处理,其细节都可隐藏在内核中,而对应用程序员透明,当进程对设备文件应用某一系统调用的时候,只要将这一系统调用转换成某种设备函数就足够了,其中设备驱动程序定义了这些函数,接下来看看这些设备类型。其中应用层,文件系统层,通用块设备层和设备驱动程序之间的关系如下图,这里贴出来供大家了解一下。读写块设备如下:

  先介绍块设备,设备驱动在驱动程序初始化时为自己注册,将这个驱动程序加入内核的驱动程序表中,并将设备号映射到数据结构block_device_operations中,数据结构block_device_operations包含了系统中启动和停止给设定块设备的函数(在include/linux/fs.h上。

struct block_operations{int (*open) (struct inode *,struct file *);int (*release) (struct inode *,struct file*);  //open()和release()都是同步的int (*ioctl) (struct node *,struct file *,unsigned, unsigned long);int (*media_changed) (struct gendisk *);int (*revalidate_disk) (struct gendisk *);struct module *owner;
};

  从处理器的角度来看,在适合的cidao4上定位磁头并将磁盘转到相应的块要花费相当长的时间,这种延迟迫使内核实现了系统请求队列,在Linux2.6中,每个块设备都有自己的请求队列,以便管理对该设备的IO口请求,进程只有在获得请求队列锁之后才能 更新设备的请求队列,让我们先来看看request_queue结构(这些代码都是自己敲出来的,然后分析,分析不好的请各位大神批评改正。)这些代码都可以在include/linux/blkdev.h中查看。

struct request_queue
{struct list_head queue_head;  //指向请求队列对首的指针struct request  *last_merge;  //加到请求队列的最后一个请求elevator_t  elevator;      //这个不懂,求大神指教struct request_list rq;     //由两个wait_queue组成,分别用于块设备读请求队列和写请求队列
...request_fn_proc *request_fn;merge_request_fn *back_merge_fn;merge_request_fn *front_merge_fn;merge_requests_fn *merge_requests_fn;make_request_fn *make_request_fn;prep_rq_fn *prep_rq_fn;unplug_fn *unplug_fn;merge_bvec_fn *merge_bvec_fn;activity_fn *activity_fn;      //定义调度程序相关函数来控制如何管理块设备的请求
...struct time_list unplug_timer;int unplug_thresh;unsigned long  unplug_delay;struct work_struct unplug_work;struct backing_dev_info backing_dev_info;    //用于去掉设备的IO调度函数...void *queuedata;void *activity_data;  //这些是对设备和设备驱动程序相关的队列进行管理...unsigned long  bounce_pfn;int  bounce_gfp;    //是指内核将高端内存缓存冲区的IO请求copy到低端内存缓冲区去unsigned long queue_flags;//变量queue_flags存储一个或者多个队列标志,参见下表格。

spinlock_t *queue_lock;
struct kobject kobj;
unsigned long nr_requests;  
unsigned int nr_congestion_on;
unsigned int nr_congestion_off;
unsigned short max_sectors;
unsigned short max_phys_segments;
unsigned short max_hw_segments;
unsigned short hardsect_size;
unsigned int max_segment_size;
unsigned long seg_boundary_mask;
unsigned long dma_alignment;
struct blk_queue_tag *queue_tags;
atomic_t refcnt;
unsigned int in_flight;
unsigned int sg_timeout;
unsigned int sg_reserved_size;  //前面这些变量定义了请求队列中可管理的资源
};

  Linux内核通过在设备的_init函数中调用下列函数来初始化块设备的请求队列,这些函数中,,可以看出请求对了内部的细节和相关帮助教程,在现在的Linux2.6内核中,每个块设备控制自己的锁,并且将自旋锁作为第二个参数来传递,其中第一个参数是块设备驱动程序提供的请求函数,下面的代码在drivers/block/11_rw_blk.c中查看得到。

request_queue_t *blk_init_queue(request_fn_proc *rfn,spinlock_t *lock)
{request_queue_t *q;static int printed;q = blk_alloc_queue(GFP_KERNEL);  //从内核的内存中分配空间队列,内容为0if(!q)return NULL;if(blk_init_free_list(q))  //初始化请求清单goto out_init;    //表示一直怕goto,懂但不会用if(!printed){printed = 1;printk("Using %s io schedulern",chosen_elevator->elevator_name);}if(elevator_init(q,chosen_elevator))  //这是个初始化的函数goto out_elv;q->request_fn = rfn;q->back_merge_fn = 11_back_merge_fn;q->front_merge_fn = 11_front_merge_fn;q->merge_requests_fn = 11_merge_requests_fn;q->prep_rq_fn = NULL;q->unplug_fn = generic_unplug_device;q->queue_flags = (1<<QUEUE_FLAG_CLUSTER);q->queue_lock = lock;    //上述赋值是将电梯调度程序相关的函数与该队列关联blk_queue_segment_boundary(q,0xffffffff);  //检查是否满足最小尺寸blk_queue_make_request(q,__make_request)  //设置驱动从队列删除blk_queue_max_segment_size(q,MAX_SEGMENT_SIZE);  //初始化归并段的上限blk_queue_max_hw_segments(q,MAX_HW_SEGMENTS);  //初始化物理设备可以处理的最大段数blk_queue_max_phys_segments(q,MAX_PHYS_SEGMENTS);  初始化每一请求的最大物理数目段return q0;  //返回已经初始化的队列out_elv:blk_cleanup_queue(q);out_init:kmem_cache_free(requestq_cachep,q);return NULL;  //错误事件中清除内存的一个例程
}

  代码实在太难,我知道的也只是皮毛,那些都需要好好体会,如若有补充的希望各路大神能够多加改正我的缺点,现在来看看设备操作,基本 的通用块设备有open,close,ioctl以及request函数,请求队列不能直接被访问,但是可以通过一组帮助例程来访问,如下:

struct request *elv_next_request(request_queue_t *q)

这个帮助函数返回并指向下一个请求结构的指针,驱动程序可以通过查看该元素来收集所有信息,以确定它的的大小方向以及该请求相关的任何其他自定义操作,之后通过end_request()想内核报告这一信息:

void end_request(struct request *req,int uptodate)  //在请求队列中传递elev_next_request()获得的参数
{if(!end_that_request_first(req,uptpdate,req->hrad_cur_sectors))  //传输适合的扇区数{add_disk_randomness(req->rq_disk);  //加入系统熵池,表示不懂,求大神指教,blkdev_dequeue_request(req);  //删除请求结构end_that_request_last(req);  //收集统计信息并且释放可用的数据结构}
}

  下面来介绍一下其它各种设备,与块设备不同,字符设备用来传送数据流,所有串行设备都是字符设备,与字符设备类似,网络设备的数据在物理层上串行传输,而时钟设备是基于硬件脉搏跳动的设备,其实就是时钟相关的,还有那终端设备,这里就稍微提及一下。因为这些都和输入输出相关,大家只要有个印象就行了。

小结

  结束了分析代码之旅,小结一下今天主要的内容,今天主要分享的是Linux内核是如何处理输入输出操作的,具体讨论了Linux是如何表示块设备和它的接口的,也介绍了Linux调度程序并且重点分析了请求队列,上述敲的代码,我也还有好多不懂,只能自己慢慢去体会了,希望各路大神看了之后能够稍加提醒一下

kmem 反编译linux内核_24小时学通Linux内核之如何处理输入输出操作相关推荐

  1. 24小时学通linux视频教程下载

    24小时学通linux视频教程下载 <楚广明24小时学通linux>引用:伏了好长时间,今天总算又一次的为大家带来一点点儿新东西,准备了一段时间后我为大家推了这一套24小时学通linux系 ...

  2. 24小时学通Linux内核之构建Linux内核

    今天是腊八节,说好的女票要给我做的腊八粥就这样泡汤了,好伤心,好心酸呀,看来代码写久了真的是惹人烦滴,所以告诫各位技术男敲醒警钟,不要想我看齐,不然就只能和代码为伴了的~~话说没了腊八粥但还是有代码, ...

  3. 24小时学通LINUX内核系列

    http://www.cnblogs.com/lihuidashen/category/667475.html 转载于:https://www.cnblogs.com/zengkefu/p/55583 ...

  4. 8天学通MongoDB——第四天 索引操作

    原文:8天学通MongoDB--第四天 索引操作 这些天项目改版,时间比较紧,博客也就没跟得上,还望大家见谅. 好,今天分享下mongodb中关于索引的基本操作,我们日常做开发都避免不了要对程序进行性 ...

  5. 深度linux_工程师深度:学通Linux内核(含详细代码)

    内核探索工具类 Linux的具体概述这里就不多说了,今天主要讲的是Linux内核中常用的数据结构和语法的使用,并简述一些工具和实用程序,从而获取理解内核内幕所需要的信息,还会介绍一下在每个内核子系统所 ...

  6. linux操作系统基础北京邮电大学出版社,Linux操作系统与实训教程

    1.理想的Linux上机实践课程 每周一次.每次三小时的学与练 本书所有例题讲解,均经过鸟哥在大专院校实施多年来的测试,对于学生的理解具有相当满意的效果. 2. 提供一致性教学环境 让学习者不再有陌生 ...

  7. 内核该怎么学?Linux进程管理工作原理(代码演示)

    前言:Linux内核里大部分都是C语言.建议先看<Linux内核设计与实现(Linux Kernel Development)>,Robert Love,也就是LKD. Linux是一种动 ...

  8. linux定时任务每小时_在Linux平台下每5、10或15分钟执行一次定时任务(Cron Job)...

    本文介绍如何在Linux平台下每5.10或15分钟运行一次cron命令,即执行一次定时任务(Cron Job). 前言 Cron job是按指定间隔执行的任务,可以将任务安排为按分钟,小时,每月的某天 ...

  9. Linux内存 匿名页,学点linux之四:内存

    内存也是一大块 第二天·内存 分页机制 缓冲区溢出攻击,注意rw权限保护 用户态不能访问内存态,inter,amd的漏洞,meltdown,从用户空间偷取了内核空间数据,熔断漏洞 内存分zone DM ...

最新文章

  1. IT男人必学的20大泡妞妙招
  2. 智源-AI Time 5 | 无人驾驶距离我们还有多远?(活动报名)
  3. 【swift学习笔记】二.页面转跳数据回传
  4. PAT甲级1049 Counting Ones (30 分):[C++题解]统计1的个数、数位统计
  5. PHP-mysql基础
  6. 一个简单的你好,世界! 使用 Boost.MPI broadcast() 的示例
  7. 临近年关,修复ASP.NET Core因浏览器内核版本引发的单点登录故障
  8. python面试题之Python是如何进行内存管理的
  9. centos下使用yum命令安装php mcrypt扩展
  10. iPhone X 穿越回 1957 年计算力相当的电脑,将会是什么样?
  11. 微信小程序 View:flex 布局
  12. 简单工厂模式-Simple Factory Pattern
  13. VMware虚拟机不能连接USB的问题
  14. 数据结构线性表-----静态链表
  15. php 过滤微信符号昵称,PHP处理微信昵称特殊符号过滤的方法
  16. python数据拟合之scipy.optimize.curve_fit
  17. Windows窗口消息大全
  18. java 1.8下载_jre1.8官方下载-JAVA运行环境(jre8 64位)1.8.0.25 官网最新版【离线版】下载_东坡手机下载...
  19. 客户端专项测试-启动时间测试
  20. 抖音seo源码二次开发,短视频seo源码二次开发

热门文章

  1. npm i 命令长时间卡住的解决办法
  2. 进程间传递文件描述符--sendmsg,recvmsg(可用)
  3. 从零学React Native之01创建第一个程序
  4. 写给新入职的毕业生们
  5. wpf之auto与*的区别
  6. RAID5阵列掉盘显示未初始化---解决过程
  7. python立方尾不变代码_对于这个蓝桥杯立方尾不变题我用java程序做的,正确结果应该是36,为什么我这样写结果就是12,如...
  8. pma mysql_mysql pma怎么看当前连接数
  9. tcp测试监听工具_高清无码多图详解!性能测试六大核心体系(没人的时候偷偷看)...
  10. linux 内存性能评估,内存性能评估工具vmstat/free/smem使用与解读