Linux2.6.29内核的get_user_pages的改进

简介:

在最新的2.6.29内核中,对get_user_pages做了一个改善,主要就是颗粒问题,以前的实现中,在get_user_pages之后才可以处理诸如“本进程已经死亡”的信息,这样的话就做了很多无用功,这在古老的系统问题不大,但是现在都是大并发大负载的系统,任何处理都要很大的付出,因此在目前的情况下,必须改善一些情况。试想一种情况,如果一个进程p已经被oom_killer选中,oom_killer在一个cpu运行,而p在另外cpu运行,它们是并发的,那么p必然在返回用户空间时才可以得知自己被杀,那么处于内核的p如果要是要调用get_user_pages的话,那么将会为它分配很多它根本没有机会再用的页面,这些页面将瞬间被释放。为了不让这种情况发生,在调用get_user_pages的时候,在get_user_pages函数的最前面,先要判断当前进程的状态,然后再决定是否进行这一次的get_user_pages操作,于是就有了2.6.28中的函数有以下形式:

int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, ...)

{

...//以下的if语句在__get_user_pages每要获取一个页面的时候都要判断从而使得检查点比较细而不是在函数最开始做一次判断。

if (unlikely(test_tsk_thread_flag(tsk, TIF_MEMDIE))) //察看是否已经被杀,如果是的话就不再继续下去了,继续下去也是没有意义的。

return i ? i : -ENOMEM;

...

}

这样做的话,看起来已经很不错了,但是真的就完美了吗?还差得远,想象一下在何种情况下进程p会被杀死,那情况当然多了去了,不一定非要是oom_killer将进程p杀死,比如在多核心处理器中,随时都有可能出现在一个cpu上运行的进程杀死在另一个cpu的核心态运行的进程,而这个核心态的进程或许就要调用get_user_pages函数,于是这个问题在多核心处理器的系统上更加明显,试想一种真实的情况,那就是一个监测进程发现另一个进程占用了过多的内存,于是根据用户设置的策略,它要杀死这个占用内存过多的进程而不管这个进程处于什么状态,于是很有可能这个进程马上就要调用get_user_pages了,2.6.29对get_user_pages新的补丁可以捕捉到这种情况从而避免了做无用功,于是新的补丁如下:

int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, ...)

{

...//以下的if语句替换2.6.28中的判断TIF_MEMDIE标志的语句,不仅仅在oom时退出,只要是被kill了都不再继续

if (unlikely(!ignore_sigkill && fatal_signal_pending(current)))

return i ? i : -ERESTARTSYS;

...

}

fatal_signal_pending的意义很明显,就是被SIGKILL附体了,马上就命归黄泉了,那么ignore_sigkill是做什么的呢?我们看一下它的定义:

int ignore_sigkill = !!(flags & GUP_FLAGS_IGNORE_SIGKILL);

这个定义出现在__get_user_pages最开始的地方。这个ignore_sigkill到底是什么意思呢?从那个if判断可以看出在ignore_sigkill为真的情况下,即使有SIGKILL附体也无所谓,继续进行而不退出,这就使得在SIGKILL附体的情况下出现一个不退出函数的空子,那么这个空子在什么时候可以钻呢?我们想象一种情况,就是在进程正在解除页面锁定的情况下被杀死了,被SIGKILL附体的时候它已经进入了__mlock_vma_pages_range但是还没有进入__get_user_pages,如果这种情况下在__get_user_pages里面直接退出的话,将会导致一些页面无法解除锁定,其实如果这些页面仅仅归被杀进程所有,那么这无关紧要,毕竟是要死的人了,咋折腾都可原谅,并无大碍,可是如果是共享页面的话,这将是不希望的,因为可能仅此被杀进程需要锁定这些页面,比如一个实时进程需要锁定一些共享库,但是别的共享此库的进程并不需要锁定库页面,那么如果这个实时进程被杀而且没有来得及解除锁定那些库的页面,那么这些页面将永远常驻内存,这虽然没有什么大问题但是毕竟不是系统的本意。实际情况应该是,一个参与者在参与一件事时如果做了什么,那么它退出的时候一定要清理,使得现场和它没有来的时候一样。于是2.6.29就有了以下补丁:

static long __mlock_vma_pages_range(struct vm_area_struct *vma..., int mlock)

{

...

if (!mlock)

gup_flags |= GUP_FLAGS_IGNORE_VMA_PERMISSIONS | GUP_FLAGS_IGNORE_SIGKILL;

...

}

于是,添加了这些代码以后,get_user_pages就不会在SIGKILL附体的情形下耽搁过久的时间了,唯一的例外就是在unlock页面的时候会在SIGKILL的情况下也会放get_user_pages一马,让它做完善后工作。为何看起来,get_user_pages和这个补丁很“亲热”,因为在get_user_pages中可能会分配页面,而在此时分配页面或者曾经的分配页面操作中可能会oom,从而很有可能当前进程已经被SIGKILL附体,其实,只有在物理页面相关的机制操作中才可能进行oom_killer操作,进而使SIGKILL附于某个进程,很有可能就是正在分配物理页面的进程,而get_user_pages就是这样一个需要分配页面的函数。

加上这个补丁后不见得性能会有多少提高,但是可以保证的是,系统可以将一些做无用功的时间用来做正经的事情,系统不一定会有做无用功的情况,但是一旦有了,而且在get_user_pages中,那么这个补丁就有了意义。


 本文转自 dog250 51CTO博客,原文链接:http://blog.51cto.com/dog250/1273931

相关文章
|
1月前
|
存储 Linux 数据处理
探索Linux操作系统的内核与文件系统
本文深入探讨了Linux操作系统的核心组件,包括其独特的内核结构和灵活的文件系统。文章首先概述了Linux内核的主要功能和架构,接着详细分析了文件系统的工作原理以及它如何支持数据存储和检索。通过比较不同的文件系统类型,本文旨在为读者提供一个关于如何根据特定需求选择合适文件系统的参考框架。
|
7天前
|
Linux API 调度
技术笔记:Linux内核跟踪和性能分析
技术笔记:Linux内核跟踪和性能分析
|
2月前
|
安全 算法 网络协议
探索Linux操作系统的内核管理
【5月更文挑战第31天】本文将深入探讨Linux操作系统的内核管理机制,包括其设计原则、主要组件以及它们如何协同工作以提供高效的系统性能。通过分析Linux内核的关键特性和功能,我们将揭示这一开源操作系统如何在各种计算环境中保持其稳定性和灵活性。
|
2月前
|
机器学习/深度学习 人工智能 负载均衡
深度解析:Linux内核调度策略的演变与优化
【5月更文挑战第30天】 随着计算技术的不断进步,操作系统的性能调优成为了提升计算机系统效率的关键。在众多操作系统中,Linux因其开源和高度可定制性而备受青睐。本文将深入剖析Linux操作系统的内核调度策略,追溯其历史演变过程,并重点探讨近年来为适应多核处理器和实时性要求而产生的调度策略优化。通过分析比较不同的调度算法,如CFS(完全公平调度器)、实时调度类和批处理作业的调度需求,本文旨在为系统管理员和开发者提供对Linux调度机制深层次理解,同时指出未来可能的发展趋势。
|
2月前
|
算法 安全 Linux
探索Linux内核的虚拟内存管理
【5月更文挑战第20天】 在本文中,我们将深入探讨Linux操作系统的核心组成部分之一——虚拟内存管理。通过剖析其关键组件和运作机制,揭示虚拟内存如何提供高效的内存抽象,支持庞大的地址空间,以及实现内存保护和共享。文章将重点讨论分页机制、虚拟内存区域(VMAs)的管理、页面置换算法,并简要分析这些技术是如何支撑起现代操作系统复杂而多变的内存需求的。
|
16天前
|
Linux
查看linux内核版本
在Linux中查看内核版本可使用`uname -r`、`cat /proc/version`、`lsb_release -a`(若安装LSB)、`/etc/*release`或`/etc/*version`文件、`dmesg | grep Linux`、`cat /sys/class/dmi/id/product_name`、`hostnamectl`、`kernrelease`(如果支持)、`rpm -q kernel`(RPM系统)和`dpkg -l linux-image-*`(Debian系统)。
26 4
|
17天前
|
安全 Linux 数据处理
探索Linux的kmod命令:管理内核模块的利器
`kmod`是Linux下管理内核模块的工具,用于加载、卸载和管理模块及其依赖。使用`kmod load`来加载模块,`kmod remove`卸载模块,`kmod list`查看已加载模块,`kmod alias`显示模块别名。注意需有root权限,且要考虑依赖关系和版本兼容性。最佳实践包括备份、查阅文档和使用额外的管理工具。
|
28天前
|
运维 NoSQL Ubuntu
深入理解Linux中的"crash"命令:内核崩溃的调试利器
`crash`是Linux内核崩溃调试工具,用于分析内核崩溃转储文件,提供GDB-like的交互式CLI。通过加载`vmcore`文件和内核映像,管理员可以查看系统状态、调用栈、内存布局等。安装`crash`可使用包管理器,如`apt-get`或`yum/dnf`。尽管有学习曲线且依赖转储文件,但`crash`在系统故障排查中极其重要。
|
2月前
|
Linux
探索Linux操作系统的内核模块
本文将深入探讨Linux操作系统的核心组成部分——内核模块,揭示其背后的工作机制和实现方式。我们将从内核模块的定义开始,逐步解析其加载、卸载以及与操作系统其他部分的交互过程,最后探讨内核模块在系统性能优化中的关键作用。
|
23天前
|
Linux 编译器 C语言
编译Linux内核:基础、重要性和交叉编译方法
Linux内核作为操作系统的心脏,负责管理计算机的硬件资源,同时也是运行所有其他程序的基础。理解如何编译Linux内核对于系统管理员、开发者乃至高级用户来说都是一项极其宝贵的技能。本文将介绍编译Linux内核的基本知识、编译的重要性、具体步骤以及交叉编译的概念。
47 0