- 博客(31)
- 资源 (14)
- 收藏
- 关注
原创 启动shell环境
6.3 启动shell环境<br />init_post函数来自同一个文件的814行:<br /> <br />811/* This is a non __init function. Force it to be noinline otherwise gcc<br /> 812 * makes it inline to init() and it becomes part of init.text section<br /> 813 */<br /> 814static noinline int init
2011-02-01 02:52:00 2141
原创 子系统的初始化
6.2 子系统的初始化<br />所以接下来说do_basic_setup函数,任然是来自init/main.c:<br /> <br />778/*<br /> 779 * Ok, the machine is now initialized. None of the devices<br /> 780 * have been touched yet, but the CPU subsystem is up and<br /> 781 * running, and memory and process m
2011-02-01 02:49:00 3210
原创 创建1号进程
6 后start_kernel时代<br />至此,start_kernel()函数完成了Linux内核的初始化工作。几乎每天内核部件都是由这个函数进行初始化的,下面让我们再来回顾一下其中最重要的部分:<br /> <br />● 调用setup_arch()函数,根据处理器硬件平台设置系统;解析linux命令行参数;设置0号进程的内存描述结构init_mm;系统内存管理初始化;统计并注册系统各种资源;以及其它项目的初始化等。<br />● 调用sched_init()函数来初始化调度程序。<br />
2011-02-01 02:42:00 2866 5
原创 安装根文件系统
5.12 安装根文件系统<br />start_kernel下步是另一个重要的函数,678行的vfs_caches_init,用于初始化VFS那些数据结构的slab缓存,来自fs/dcache.c:<br /> <br />2355void __init vfs_caches_init(unsigned long mempages)<br />2356{<br />2357 unsigned long reserve;<br />2358<br />2359 /* Base ha
2011-02-01 02:40:00 3029
原创 走进start_kernel尾声
5.11 走进start_kernel尾声<br />中断体系建立起来后,虽然后面还有很多行代码,但是都是些比较好理解的初始化函数了,也就是说start_kernel进入尾声了。5.11.1 初始化slab的后续工作<br />继续分析start_kenel的下一个函数,613行,profile_init函数,用于对系统剖析做相关初始化,系统剖析用于系统调用:<br /> <br />int __ref profile_init(void)<br />{<br /> int buffer_byt
2011-02-01 02:36:00 3366
原创 初始化定时器中断
5.10.4 初始化定时器中断<br />回到start_kernel,612行time_init函数:<br />void __init time_init(void)<br />{<br /> late_time_init = x86_late_time_init;<br />}<br /> <br />函数x86_late_time_init实际上是初始化tsc时钟源。在time_init中只是把该函数的地址赋给全局变量late_time_init,以后某个时刻肯定会调用它的,这里先提前详
2011-02-01 02:34:00 3239
原创 软中断初始化
5.10.3软中断初始化<br />open_softirq结束后,init_timers就结束了,整个内核就可以享受时钟服务了,接下来start_kernel的609行调用hrtimers_init。由于我们没有配置CONFIG_HIGH_RES_TIMERS,所以这个函数仅仅是把全局notifier_block变量hrtimer_cpu_notify加入通知链,供将来的内核各模块使用。<br /> <br />然后,start_kernel的610行调用softirq_init来初始化整个软中断系统:<
2011-02-01 02:33:00 2464
原创 初始化本地软时钟
5.10.2 初始化本地软时钟<br />native_init_IRQ结束后,init_IRQ也就结束了,回到start_kernel中,607行,prio_tree_init函数很简单:<br /> <br />void __init prio_tree_init(void)<br />{<br /> unsigned int i;<br /> <br /> for (i = 0; i < ARRAY_SIZE(index_bits_to_maxindex) - 1; i++)<
2011-02-01 02:32:00 2529
原创 设置APIC中断服务
5.10 初始化中断处理系统<br />start_kernel接下来要做的事是初始化中断处理系统。整个内核的中断系统的核心就是我们在“初始化中断描述符表”里面设置的那个中断描述符表。而这个表的前19个表项我们已经在“初始化异常服务”中设置为了一些中断和异常的服务。内核接下来会如何设置其余的表项呢?<br /> <br />前面提到过高级可编程中断控制器APIC,这里简单地提一下它的体系结构,简单地说就是由两部分组成:本地高级中断控制器(Local APIC,LAPIC),位于每个CPU中,主要负责传递中断
2011-02-01 02:30:00 4700
原创 初始化调度程序
5.9 初始化调度程序<br />回到start_kernel函数中,mm_init()执行后,所有的绝大多数内存管理的初始化都完毕,后面的代码可以开开心心的使用Linux复杂、庞大而又高效的内存管理器了。来看下一个函数,超级重点的进程调度初始化函数sched_init()。不过自从Linux 2.6.23(2007年5月),内核引入了一种所谓的完全公平调度程序(Completely Fair Scheduler,CFS),试图按照对 CPU 时间的“最大需求(gravest need)”运行任务;这有助于
2011-02-01 02:28:00 2884
原创 初始化非连续内存区
5.8.3 初始化非连续内存区<br />回到mm_init()函数,继续走,下一个函数pgtable_cache_init (),不知道咋的,是个空函数,也许是保留着以后开发吧。最后一个函数是vmalloc_init(),来自mm/vmalloc.c:<br /> <br />1088void __init vmalloc_init(void)<br />1089{<br />1090 struct vmap_area *va;<br />1091 struct vm_stru
2011-02-01 02:27:00 2227 1
原创 初始化slab分配器
5.8.2 初始化slab分配器<br />回到mm_init()函数,继续走,下一个函数kmem_cache_init(),也是重点函数,用于初始化内核slab分配体系。这个函数来自文件mm/slab.c<br /> <br />1375void __init kmem_cache_init(void)<br />1376{<br />1377 size_t left_over;<br />1378 struct cache_sizes *sizes;<br />1379
2011-02-01 02:25:00 2027
原创 启用伙伴算法
5.8 初始化内存管理<br />回到start_kernel,下一个函数执行mm_init()。这个函数很重要了,来自同一个文件。<br /> <br />static void __init mm_init(void)<br />{<br /> /*<br /> * page_cgroup requires countinous pages as memmap<br /> * and it's bigger than MAX_ORDER unless SPARSE
2011-02-01 02:22:00 3663 1
原创 初始化异常服务
5.7 初始化异常服务<br />继续走,start_kernel的583行,sort_main_extable,把编译期间,kbuild设置的异常表,也就是__start___ex_table和__stop___ex_table之中的所有元素进行排序。<br /> <br />584行,调用trap_init函数,重要的函数,初始化中断向量表。该函数来自arch/x86/kernel/traps.c<br /> <br />882void __init trap_init(void)<br /> 883{
2011-02-01 02:20:00 3147
原创 触碰虚拟文件系统
5.6 触碰虚拟文件系统<br />回到start_kernel中,下面我们该第一次接触文件系统了,582行执行vfs_caches_init_early:<br /> <br />void __init vfs_caches_init_early(void)<br />{<br /> dcache_init_early();<br /> inode_init_early();<br />}<br /> <br />vfs_caches_init_early调用两个函数dcache_
2011-02-01 02:19:00 2732
原创 利用early_res分配内存
5.5 利用early_res分配内存<br />回到start_kernel中,570行,page_alloc_init()函数:<br />void __init page_alloc_init(void)<br />{<br /> hotcpu_notifier(page_alloc_cpu_notify, 0);<br />}<br /> <br />这个函数会调用hotcpu_notifier函数。当然,在编译选项CONFIG_HOTPLUG_CPU起作用时,这个函数才有效。这个编译选
2011-02-01 02:13:00 2503
原创 初始化内存管理区列表
5.4 初始化内存管理区列表<br />回到start_kernel函数,569行的build_all_zonelists()函数,来自mm/page_alloc.c:<br /> <br />2815void build_all_zonelists(void)<br />2816{<br />2817 set_zonelist_order();<br />2818<br />2819 if (system_state == SYSTEM_BOOTING) {<br />2820
2011-02-01 02:11:00 3437
原创 设置每CPU环境
5.3 设置每CPU环境<br />回到start_kernel,563行调用mm_init_owner函数,将init_mm的owner字段指回init_task。这个函数可以说进入start_kernel以来最简单的函数了。继续走,setup_command_line也很简单:<br /> <br />static void __init setup_command_line(char *command_line)<br />{<br /> saved_command_line = allo
2011-02-01 02:09:00 6255
原创 scsi命令的第二次转变
1.6.6 scsi命令的第二次转变<br />一旦这种关系建立好了以后,就可以开始执行请求了。来看blk_execute_rq(),来自block/ll_rw_blk.c:<br /> <br /> 2616 int blk_execute_rq(request_queue_t *q, struct gendisk *bd_disk,<br /> 2617 struct request *rq, int at_head)<br /> 2618 {<br /
2011-02-01 02:02:00 3090
原创 scsi命令的第一次转变
1.6.5 scsi命令的第一次转变<br />前面介绍了读写文件时,是通过sd_init_command设置的scsi_cmnd命令结构,其实我们也可以通过scsi_execute_req函数直接发送scsi命令,不过需要两次转变。<br /> <br />仍然以scsi磁盘举例,最初scsi这边发送的是scsi命令,可是从block走就得变成request,然而走到磁盘那边又得变回scsi命令,换言之,这整个过程scsi命令要变两次身。<br /> <br />比如,我们想获得磁盘的容量,就可以直接调用
2011-02-01 01:59:00 5617
原创 scsi命令的执行
1.6.4 scsi命令的执行<br />负责执行具体scsi命令的函数是scsi_dispatch_cmd,来自drivers/scsi/scsi.c:<br /> <br /> 468 int scsi_dispatch_cmd(struct scsi_cmnd *cmd)<br /> 469 {<br /> 470 struct Scsi_Host *host = cmd->device->host;<br /> 471 unsigned lon
2011-02-01 01:56:00 3771
原创 scsi命令的执行
1.6.4 scsi命令的执行<br />负责执行具体scsi命令的函数是scsi_dispatch_cmd,来自drivers/scsi/scsi.c:<br /> <br /> 468 int scsi_dispatch_cmd(struct scsi_cmnd *cmd)<br /> 469 {<br /> 470 struct Scsi_Host *host = cmd->device->host;<br /> 471 unsigned lon
2011-02-01 01:24:00 4243
原创 scsi块设备驱动层处理
1.6.3 scsi块设备驱动层处理<br />好了,了解完必要的scsi设备驱动知识以后,我们就可以安心分析scsi_request_fn函数了。大家回忆一下对,这个函数指针通过几次传递并最终在blk_init_queue_node()中被赋予了q->request_fn。所以这一层的重点就是这个scsi_request_fn函数。<br /> <br />在看scsi_request_fn之前,注意回忆一下scsi_alloc_queue函数的1598行至1560行还赋了三个函数指针:<br /> <b
2011-02-01 01:01:00 10455 3
原创 scsi设备驱动体系架构
1.6.2 scsi设备驱动体系架构<br />从这一层开始,整个文件读写的中心将由request转向scsi的命令结构scsi_cmnd。那么这个命令结构到底是怎么一回事呢,这还得从SCSI架构谈起。SCSI 实现了一种客户机/服务器风格的通信架构,发起者向目标设备发送命令请求。该目标处理此请求并向发起者返回响应。发起者可以是托管计算机中的一个 SCSI 设备,而 SCSI 目标则可以是一个磁盘、光盘和磁带设备或特殊设备(比如箱体设备)。<br /> <br />这里要提到一个概念——Lower Leve
2011-02-01 00:37:00 11830 1
原创 scsi总线驱动的初始化
1.6.1 scsi总线驱动的初始化<br />块设备底层驱动的核心是scsi总线层驱动,在总线层驱动之上为各种不同的scsi设备驱动,在总线层驱动之下为scsi host驱动。其在内核中的位置如下图所示:<br /><br /> <br /><br /><br />前面我们已经知道了上三层的工作,接下来大部分知识来自底下三层。<br /> <br />在Linux中scsi驱动基本分为三大层:top level,middle level以及lower level。top level为具体的scsi设备驱动
2011-02-01 00:30:00 17458 5
原创 真实的I/O调度层处理
1.5.6 真实的I/O调度层处理<br />现在我们块设备也有了,队列也有了,要提交请求也就可以开始提交了。那就让我们回到generic_make_request来研究一下如何提交请求如何处理请求吧。我们看到,函数最后调用q->make_request_fn(q, bio)。对 make_request_fn 函数的调用可以认为是 IO调度层的入口,该函数用于向请求队列中添加请求。该函数是在创建请求队列时指定的,代码如下(blk_init_queue 函数中):<br />q->request_fn =
2011-02-01 00:22:00 7133
原创 块设备I/O调度程序
1.5.5 块设备I/O调度程序<br />我们建立请求队列建的目录是,当向请求队列增加一条新的请求,即产生一个request数据结构时,通用块层会调用I/O调度程序来确定该新request将在请求队列中的确切位置。I/O调度程序试图通过扇区将请求队列排序。如果顺序地从链表中提取要处理的请求,那么就会明显减少磁头寻道的次数,因为磁头是按照直线的方式从内磁道移向外磁道(反之亦然),而不是随意地从一个磁道跳跃到另一个磁道。<br /> <br />这就是著名的电梯算法,回想一下,电梯算法处理来自不同层的上下请求
2011-02-01 00:17:00 9150 2
原创 为设备建立请求队列
1.5.4 为设备建立请求队列<br />好啦,磁盘和分区建立好了,block_device数据结构也关联起来了,回到add_disk中,我们需要调用第三个函数了,也就是blk_register_queue(disk),来建立请求队列与bio等数据结构了,让我们来仔细分析。<br /> <br /> 4079 int blk_register_queue(struct gendisk *disk)<br /> 4080 {<br /> 4081 int ret;<br />
2011-02-01 00:14:00 3303
原创 关联block_device结构
1.5.3 关联block_device结构<br />接下来是register_disk函数,来自fs/partitions/check.c:<br /> <br /> 473 /* Not exported, helper to add_disk(). */<br /> 474 void register_disk(struct gendisk *disk)<br /> 475 {<br /> 476 struct block_device *bdev;<br /
2011-02-01 00:11:00 5323
原创 建立块设备驱动环境
1.5.2 建立块设备驱动环境<br />上一节内容反映的是系统上电后,Linux初始化块设备子系统并注册了相应的块设备驱动的内容。而当我们把一块300G的硬盘插入总线的SCSI插槽中时,SCSI设备对应的probe程序就会调用alloc_disk()函数为其分配gendisk结构。<br /> <br />那么SCSI设备对应的probe程序到底是什么呢?设备驱动的研究是有一定套路的,比如说我们这里的scsi吧,必须在drivers/scsi目录下看它的Kconfig和Makefile文件。根据文件中的内
2011-02-01 00:08:00 3638
原创 块设备的初始化
1.5 块设备I/O调度层的处理<br />下面进入块设备I/O调度层,来看看q->make_request_fn方法。不过这个方法的具体函数是什么呢?别着急,要弄清这个问题还需要再补充一下块设备驱动的基础知识,不然就又走不下去了。块设备驱动程序是Linux块子系统中的最底层组件。它们从I/O调度程序中获得请求,然后按要求处理这些请求。<br /> <br />当然,块设备驱动程序是设备驱动程序模型的组成部分(也就是在sysfs中能够看到它)。因此,每个块设备驱动程序对应一个device_driver类型的
2011-02-01 00:03:00 3641 2
NFS文件系统
2012-04-08
数据结构与算法——面向对象C++设计模式
2011-11-27
高性能分布式监控系统Ganglia详解
2011-07-10
疯狂内核之——内核初始化
2011-05-30
疯狂内核之——Linux虚拟内存
2011-05-30
疯狂内核之——进程管理子系统
2011-05-30
疯狂内核之——Linux预备知识.pdf
2011-05-30
基于C++语言的GoF23种设计模式
2011-05-29
从8086到Pentium Ⅲ微型计算机及接口技术3
2010-09-24
Linux sysfs 文件系统机制详解
2009-12-14
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人