`
totoxian
  • 浏览: 1071251 次
  • 性别: Icon_minigender_2
  • 来自: 西安
文章分类
社区版块
存档分类
最新评论

linux2.6.28内核对bio完成通知的改进--集中走向分离的另一个例子

 
阅读更多

本文介绍一个例子,linux软中断是谁触发谁执行,这有点各司其职的意思,可是到了触发软中断的时候往往已经丢失触发这个“触发软中断”事件的源头,因此这种各司其职不是那么完善,于是2.6.28在bio的完成通知中完善了它。
到了触发软中断的时候往往已经丢失触发这个“触发软中断”事件的源头,这句话什么意思呢,有点拗口,还好这不是一篇文学类的文章,我们没有必要咬文嚼字, 只要明白意思就可以了。在smp中考虑一种情况,一个进程运行在一个cpu上,该进程执行了一个读文件操作,该操作一步一步向低层推进,终于到了 block层进而接触到了磁盘驱动,到了硬件层cpu就管不着了,在计算机体系结构中,cpu和io设备实际上是平级的,平等的关系,于是这个执行读操作 的进程不得不等待在一个等待队列上,进程开始睡眠,到此为止该进程有百分之九十五以上的可能性还在那个cpu上运行,进程睡眠以后,磁盘操作交给了磁盘硬 件,操作中硬件通过中断来通知操作的执行情况,很显然操作执行完毕后也是通过中断来通知的,可是被中断的cpu还是执行读文件的进程所在的那个cpu吗? 这个就不能保证了,不是说保证这点有多难,而是保证了这一点后linux的模块之间的偶合性将大大加强,中断的路由是linux内核的一个完整的模块,没有必要和进程睡眠和smp进程迁移强加联系,于是这里被中断的cpu就有百分之五十的可能不是那个读文件进程所在的cpu,我们假定不是原先的那个 cpu。
我们知道io完成操作是通过软中断来执行的,完成操作也就是唤醒原始的进程,如果是被磁盘中断的cpu来触发io完成软中断,那么由linux软中断谁触发谁执行的原则,就应该由此被中断的cpu来执行io完成软中断,实际上就是在这个cpu上唤醒了在不同的cpu上睡眠的进程,如果我们看看 try_to_wake_up函数就会发现唤醒不同的cpu上的进程的开销很大,涉及到迁移,计数,负载均衡等细节,既然不能让进程的睡眠和唤醒于中断的路由耦合,那么能否用另外一种方式让软中断路由与进程的睡眠和唤醒耦合呢?答案是肯定的,我们只需要记住原始的睡眠的进程所在的cpu,就可以在硬件中断完毕后触发软中断的时刻将软中断路由到这个被记住的cpu上,这样的话,最终的操作就是一个软中断唤醒了睡眠在当前cpu上的进程,这个开销是很小的,直 接唤醒,负载均衡几乎是没有必要的。
了解到这点以后,代码就非常容易理解了,关键就是跟踪进程睡眠时所在的cpu编号,以往我们的操作是以睡眠->软中断->唤醒这个过程为中心 的,可是这个以静态过程为中心的结构很难在smp上扩展,它只在单cpu上串行处理的的时候十分有效,在smp上必须以数据为中心,简单看一下代码:

static void trigger_softirq(void *data)

{

struct request *rq = data;

unsigned long flags;

struct list_head *list;

local_irq_save(flags);

list = &__get_cpu_var(blk_cpu_done);

list_add_tail(&rq->csd.list, list);

if (list->next == &rq->csd.list)

raise_softirq_irqoff(BLOCK_SOFTIRQ);

local_irq_restore(flags);

}

static int raise_blk_irq(int cpu, struct request *rq)

{

if (cpu_online(cpu)) { //只在特定的cpu上进行路由操作

struct call_single_data *data = &rq->csd;

data->func = trigger_softirq;

...

__smp_call_function_single(cpu, data); //smp路由函数执行的函数

return 0;

}

return 1;

}

void blk_complete_request(struct request *req)

{

...

local_irq_save(flags);

cpu = smp_processor_id();

group_cpu = blk_cpu_to_group(cpu);

if (test_bit(QUEUE_FLAG_SAME_COMP, &q->queue_flags) && req->cpu != -1)

ccpu = req->cpu;

else

ccpu = cpu;

if (ccpu == cpu || ccpu == group_cpu) { //本cpu就是原始cpu

struct list_head *list;

do_local:

list = &__get_cpu_var(blk_cpu_done);

list_add_tail(&req->csd.list, list);

if (list->next == &req->csd.list)

raise_softirq_irqoff(BLOCK_SOFTIRQ); //直接在本cpu上触发软中断

} else if (raise_blk_irq(ccpu, req)) //否则路由软中断

goto do_local;

local_irq_restore(flags);

}

void init_request_from_bio(struct request *req, struct bio *bio)

{

req->cpu = bio->bi_comp_cpu; //追踪了原始的cpu

...

}

bio_set_completion_cpu函数可以手工设定软中断的路由目的地:

static inline void bio_set_completion_cpu(struct bio *bio, unsigned int cpu)

{

bio->bi_comp_cpu = cpu;

}

以 上就是简要的代码逻辑,实际上代码本身并不重要,重要的是思想,和上一篇文章一样,本文也是一个集中走向分离的例子,各司其职的另一种表达方式就是分工,在分布式大行其道的今天分工中隐含的意思就是协作。看看linux的新内核,都在向协作也就是各司其职的方向进化,以往串行的时代已经过去,再也不要指望将什么事情都交给一个中央机构了。

分享到:
评论

相关推荐

    linux-2.6.28 版本内核

    我想这款linux-2.6版本的内核是最适合那些刚初学linux内核的人群,里面的模块驱动和内核的裁剪都十分的清晰

    Linux 2.6.28 内核配置选项详解

    通过以上对Linux 2.6.28 内核配置选项的详细解析,我们可以看到内核配置不仅涉及到了硬件支持、文件系统、网络服务等多个方面,还涵盖了安全性和模块管理等高级功能。正确地配置内核对于优化系统性能和确保系统稳定...

    linux2.6.28内核驱动程序

    Linux 2.6.28是一个历史悠久但仍然具有重要研究价值的内核版本。本文将深入探讨在这个内核版本下,如何实现系统调用、编写字符设备驱动以及理解内存分配管理机制。 **一、系统调用** 系统调用是用户空间程序与操作...

    linux-2.6.28内核配置中文手册.pdf

    本手册针对的是Linux 2.6.28内核版本,这是一个历史悠久且广泛应用的版本,其配置对于理解Linux内核工作原理和优化系统性能至关重要。 在进行Linux内核配置时,`make menuconfig` 是一个关键步骤。这个命令启动了一...

    linux2.6.28 usbcamera 调试

    总之,Linux 2.6.28 USBCamera的调试是一个涉及硬件、驱动、用户空间应用和内核交互的综合性任务。通过实践和学习,不仅可以提升对Linux内核的理解,还能掌握处理硬件问题的技能。这个过程虽然可能充满挑战,但收获...

    s3c-linux-2.6.28

    Linux内核2.6.28是一个历史悠久的版本,它在2008年发布,包含了众多性能改进和新特性。 S3C6410是一款基于ARM11架构的微处理器,广泛应用于移动设备、嵌入式系统和工业控制领域。它具有高性能、低功耗的特点,支持...

    linux-2.6.28内核配置中文手册

    Linux 2.6.28内核是Linux发展历史上的一个重要里程碑,发布于2008年,包含了众多改进和新特性。它引入了更好的电源管理、增强的网络性能、改进的文件系统支持,以及对新硬件的兼容性增强。配置内核时,我们需要了解...

    Linux-2.6.28实验

    【Linux-2.6.28实验】是一个针对计算机科学与技术专业学生的实验课程,旨在让学生深入理解Linux操作系统,特别是嵌入式环境下的系统开发。实验涵盖了从开发平台的构建到驱动程序加载的全过程,通过理论与实践的结合...

    OK6410-A开发板LINUX2.6.28用户手册.pdf

    根据提供的文件内容,这是一本名为《OK6410-A开发板LINUX2.6.28用户手册》的详细教程,该手册介绍了如何在OK6410-A开发板上安装、配置及开发基于LINUX 2.6.28内核的操作系统。以下是这本用户手册中涵盖的主要知识点...

    linux_kernel_config 中文手册(2.6.28)

    《Linux内核配置指南》是理解Linux内核配置过程的关键文档,特别是在处理版本2.6.28时。内核配置是Linux系统的核心部分,它决定了操作系统如何与硬件交互、支持哪些功能以及优化性能的方式。这份手册对于系统管理员...

    Linux 内核的发展--千锋培训

    总结来说,2.6.28和2.6.29版本的Linux内核更新反映了Linux内核持续的演进和创新,不仅在文件系统、内存管理、图形处理、存储支持和网络连接等方面带来了显著改进,还展示了对新兴技术的适应性。这些发展对于Linux在...

    linux-2.6.28在mini2440上的移植之初步移植

    - **Linux-2.6.28**: 这是Linux内核的一个版本,发布于2008年12月13日。它对硬件支持进行了大量的更新,并包含了许多新的特性和改进。此版本在当时的嵌入式设备中非常受欢迎,特别是在那些对稳定性和性能有较高要求...

    基于S3C2440 2.6.28内核的Mplayer移植

    在Mplayer主目录下创建一个新的脚本文件`build-arm.sh`,用于设置`configure`命令。脚本内容如下: ```shell #!/bin/sh ./configure --cc=arm-linux-gcc \ --prefix=$PWD/build \ --host-cc=gcc \ --target=arm-...

    linux-2.6.28移植过程

    - **Linux-2.6.28移植过程**:此标题表明文章主要介绍如何将Linux 2.6.28版本的内核移植到特定硬件平台——S3C2410上。 #### 描述解读 - **基于S3C2410的Linux-2.6.28移植**:这段描述强调了移植的目标平台是S3C...

    含有gspca驱动的linux内核2.6.28

    含有gspca驱动的linux内核2.6.28

    Linux Kernel Configuration Manul(2.6.28) Linux-Kernel核心中文手册内核图解

    Linux Kernel Configuration Manul(2.6.28) Linux_Kernel核心中文手册(内核图解)pdf chm

    2.6.28内核增加系统调用[归类].pdf

    在Linux操作系统中,系统调用是用户空间与内核空间交互的重要途径,允许应用程序执行只有内核才能完成的任务。在2.6.28内核版本中增加自定义的系统调用,通常需要遵循一系列步骤。以下是详细的操作过程: 1. **下载...

    OK6410-A开发板LINUX2.6.28用户手册

    ### OK6410-A开发板LINUX2.6.28用户手册知识点解析 #### 一、前言 OK6410-A开发板是一款基于Linux 2.6.28操作系统的嵌入式开发平台,适用于各种嵌入式应用开发场景。本手册旨在指导用户如何使用该开发板进行软件...

    2.6.28内核增加系统调用[文].pdf

    本文档详细介绍了如何在Linux 2.6.28内核中增加自定义系统调用的步骤,这对于理解操作系统底层原理和进行内核开发至关重要。 首先,你需要下载2.6.28版本的内核源代码,可以从官方网站或其他可靠来源获取。一旦下载...

Global site tag (gtag.js) - Google Analytics