博客

让静态分析更容易些

Making static analysis easier
By Jonathan Corbet
June 22, 2011

翻译:林业

有件事几年来已经很清楚了,那就是静态分析工具有极大的提高我们所编写软件的质量的潜力,计算机有条件分析源代码并且寻找那些可以标示漏洞的 patterns。“Stanford Checker”(后来被 Coverity 商业化了)已经在许多免费软件代码库中找到了大量的缺陷。但就是在免费软件社区之内,我们自己开发的工具相对缺乏并且比较原始,不过,这种情况或许已经要结束了,我们已经开始看到若干可能成为静态分析工具集基础的开发框架了。

一些关键的变动已经出现在编译器套件中。编译器目前已对代码执行了详细的分析来生成优化的2进制码;如果利用那些分析来做其它的事情是很自然的。其中的一些已经出现在编译器本身之内;GCC和LLVM可以生成一个比以往更广泛的警告集。这些警告是一个好的开始,但是还有更多的事可以去做,特别是让一个项目可以生成自己专有的项目检查分析工具。因为无论什么大小规模的项目都趋向于拥有自己本身的而与其他不同的不变量和规则。

几年来FSF一直反对将分析模块通过插件机制添加到GCC,因为害怕插件机制会允许私有模块的产生。经过几年时间的考虑,因为对专有模块处理的担忧,FSF改写了运行时模块的许可证例外部分;到这时,GCC才有了对插件模块的支持。虽然这个特性的作用现在还相对较小,但却是一个情况即将改变的标志。

Mozilla项目是一个对插件机制较早的使用者,它创造了两个模块(Dehydra and Treehydra)来让开发者编写用Javascript写出的分析代码。这些工具已经展示出了其在Mozilla之内的作用,但是这方面的开发似乎停止了。其邮件列表处于垂死状态并且其软件看起来也似乎好久没有更新了。

一个替代的选择是GCC MELT。这个项目提供了一个相当广泛的插件地址以允许使用类Lisp语言来编写分析代码,这份代码被转换成C语言,然后编译出一个可被编译器调用的插件。MELT有很好的文档;以及许多关于其应用教程的幻灯片。

MELT看起来似乎是一个能胜任的系统,但是看起来似乎并没有太多为其而写的模块。人们并不希望必须看很多文档后才能理解该系统。基本提示是以如下开头的:“首先你要理解 GCC的主要内部表现(notably Tree & Gimple & Gimple/SSA)。”MELT作者Basile Starynkevitch的130页关于MELT的讲解幻灯片的前85页全都是介绍GCC材料。换一种说法,使用MELT需要对GCC有深入的理解;其并不是一个行外人士可以快速上手的系统,可以使用的简单示例的缺乏也同样是没什么帮助。

最近,David Malcolm宣布了一个新的框架的发布,该框架允许产生一些与编译器共同运行的Python脚本插件。他的原始目标就是要创造一些帮助 Python 项目(CPython)开发的工具。其代码中最重要的检查部分就是在努力确保对象的引用计数被正确的管理。但是他认为自己的工具对其它的一些项目甚至是对GCC本身的新特性设计也是有潜在作用的。

第一眼看上去,David的gcc-python-plugin机制承受着和MELT一样的困难 - 最初的学习曲线是不合理的。它同样是一个很年轻且不完整的项目;David自己也承认,只推出了他急需的功能性的部分。分析代码看起来很接近了,可是,在编译器中直接运行脚本的机制确实比MELT的compile-from-Lisp要自然些。相比MELT,这可能会吸引更多的用户和开发人员吧。

或许它只是因为小编本人使用 Python 比在Lisp中更加熟练,所以偶自然而然的觉得基于Python是一个更好的解决方案。

无论如何,有一个结论是很清楚的:目前为GCC编写静态分析插件太难了;甚至是有才华的开发者在接触到这个问题时也需要花费很多的时间去理解编译器,才可能在这个领域取得一些成就。上面描述的这些努力是在正确方向上的一个很大的进步。很明显,现在的努力是需要在其上构建许多支持代码的基础。很难说我们什么时候才能到达那个分析代码大量涌出的临界点,现在离那个时候还很遥远。

不过,并不是所有的活动都在围绕着GCC,一个利用LLVM编译器的有趣的静态分析工具已经随着 clang 被构建出来了。关于这个工具的文档几乎没有,但是看起来它在某些方面还是很强大的,比如检测某些内存泄漏问题,间接的空指针引用,闲置价值的计算等等。一些为这个工具增加一个插件特性的补丁包也已经被贴出,但是看起来似乎它们目前也并没有走的更远。

在5月的时候,John Smith在一些开源项目中运行了 clang 想要看看会得到什么样的结果。这些结果已经被贴到了网上,它们显示了一些可被找到的潜在的问题以及检查器所产生的漂亮的HTML输出。其中一些警告明显是无效的——一个经常伴随着静态分析工具的问题——但是另外的一些看起来很值得去研究。总而言之,clang 静态分析工具看起来就像这里提到的其他工具一样,在发展过程中还处于一个相对较早的阶段,虽然所有东西都在快速运行着,但是这个工具是值得关注的。

事实上,一般而言,在静态分析领域,以下这些事情是真的:缺乏一个好的分析工具有点奇怪——考虑到我们有那么多的开发人员,有的人可能认为只需要很少人就能搞出一个静态分析工具。相比较于已经存在很多的版本控制系统,我更希望开发者去开发更好的分析工具。但是自由软件开发的天性就是人们工作在那些使他们感兴趣的问题上。随着我们静态分析工具的基础越来越好,可以期待越来越多的开发人员将会找到他们感兴趣的基础,并且乐于在其之上进行构建。而整个开发社区也会从这些结果中受益。

Topic: sohulinux

One more hop for Kermit

http://lwn.net/Articles/448636/
By Jonathan Corbet
June 22, 2011

翻译:马少兵

在过去最美好的时代,我做 VMS 系统管理员的时候,那时 ARPAnet 还是一个很小、龟速的网络,而且接入点及其有限。当一些牛人基于UUCP连接建立了USENET,Unix系统还没有被广泛使用。但已经开始出现了个人电脑,电子公告板系统也开始被建立,我们中的一些幸运儿还能够买得起1200波特的调制解调器。在那些日子里所使用的调制解调器工具是一个叫做 kermit 的小程序,并且下载是完全免费的。俺已经不记得最后一次使用调制解调器是哪个时候,但是我仍然会很有兴趣去看到,已经30多年的工程即将通过最后的过渡,和其他的一样,最终走向自由软件。

那个年代的许多系统,尤其是没有任何政府预算支持的,其“网络接口”是串口。通过该接口,我们可以连接到计算机工作,也是它让我们在那个时代获得了最早的远程服务。任何通过RS232联网的用户首先需要在计算机的RS232接口和modem的RS232接口之间交换串行数据。尽管Unix系统通过一个叫“cu”的工具来达到这个目的,但是人们还是倾向于用kermit来代替。

Kermit最早起源于美国哥伦比亚大学,是把它作为多种不同网络环境下的计算机通信的方法。相比”cu”,kermit具有容易安装到软盘、设置和使用的特点。仅仅只需要弄清有多少数据位、多少停止位、多少校验位(RS232是最流行的标准)、以及适合与调制解调器上的ATD命令相对应的类型是什么等。Kermit甚至可以对不同处理字符集之间进行转换;也可以直接同 EBCDIC主机通信。

在一个很短的时间内,Kermit开发了一些适合文件传输的功能。该协议是相当有效率的,而且它的设计还包括用于处理串口通信中偶尔出现的控制字符,将8位数据转为7位数据等。该协议的健壮性意味着,它可“工作于”任何两种类型结构的机器之间。所以在前互联网时代,Kermit成为了最流行的文件传输协议,是不足为奇的。

尽管哥伦比亚大学以源代码方式发布了Kermit的多个版本;包括从 BBS 下载,DECUS磁带等,但是从来不是自由软件。造成这样问题的主要原因是,当kermit首次发布和使用的时候,自由软件许可证还没有出现。虽然哥伦比亚大学已经考虑将代码发布到一个公共的领域,但是这种决定看起来并不是最好的。

因为我们想使得Kermit软件能够被公开共享,而不是仅仅发布到一个公共领域,虽然这看起来是矛盾的。我们觉得通过拥有版权,可以防止企业独占该软件,以及所带来的将该软件成为一种商业产品而出售的情况。因为在我们面前已经发生了一系列这样的事件,由于一些大学将自己的代码发布至公共领域,结果被公司重写,最终使得公司占据了该代码的版权。

Kermit许可证会随着时间变化而改变,但是“你可以使用在非商业化的程序中”的情况是保持不变的。Kermit许可证的最终版本允许,可以将该代码绑定在免费的操作系统之中,但是禁止在没有允许的情况下修改源代码。因此事实是,尽管Kermit许可证和Linux操作系统一样允许分发,但是由于它不是一个真正的免费软件,而导致大量的发行版最终躲避使用它。

除了免费的操作系统以外,任何人想要发布商业化与Kermit有关的系统,必须向哥伦比亚大学购买许可证($3-10/each)。

在过去,Kermit已经取得了引人注目的成绩。但是随之而来的互联网已经取代它的位置。现在利用手机,都可以运行ssh协议。RS232逐渐退出了历史舞台。内核的开发者仍然在某些情况下用串口进行调试,但是我估计,大部分的LWN读者从未考虑过什么是 null modem cable. Kermit的用户肯定会逐渐萎缩,对那些需要的人来说,仍然会被使用和购买

可能在三月份,哥伦比亚大学宣布不再支持Kermit项目的维护了。其中一个可能性是由于商业许可证的销售额减少,导致没有足够的日常管理费来维持目前的工作。在2011.7.31号以后,哥伦比亚大学将不再开发任何的代码加入到Kermit系统中,也不再提供系统支持和维护服务。已经运行了30年得工程即将结束。

哥伦比亚大学计划在Kermit系统结束以前还要做一件事情,那就是将该软件放置于BSD许可证下。C-Kermit9.0版本就携带该许可证信息;6月15号,首个测试版已经发布。9.0版本将支持FORCE-3包协议(“使用在恶劣环境下”),改进了相应的脚本、修复了很多地方的bug等。因此9.0版本的发布,大概会选取一个距离7月31号截止日期之前的某一天,不仅仅有新的功能。而且将会首次免费发布。

由于这种变化的结果,Kermit将会很快出现在你的发行版的仓库中;对于大多数的Linux用户,这一点关注度可能很小。但是对于我们中的大多数,有时候通过串口连接是唯一和系统进行通信的方式。虽然Kermit系统远不是我们唯一的选择,但它相当不错。我们很欢迎Kermit能够加入开源软件社区。

Topic: sohulinux

一个Crypt_Blowfish加密中存在的漏洞

A hole in crypt_blowfish
By Jake Edge
June 22, 2011

翻译:史玉良

最近在crypt_blowfish密码散列库中发现了一个长期以来一直存在的bug。由于crypt_blowfish加密算法已经存在多年(据称该bug可以追溯到1998或1997年!),并已广泛应用于其他安装包(例如PHP)和一些Linux发行版中;从该事件可以看到,一个广泛应用的底层库若出现bug时可能会引发相当大的麻烦。该bug对于安全性的影响不大,因为它只影响到一些不常用于做口令的字符。但对于那些存储了由该库函数而产生的散列密码的部分人来说,这个bug就会有些头疼。

密码散列技术是一个用于鉴权机制(例如登陆一个系统或网络应用)的标准技术。明文密码并不需要存储,而由明文密码派生出来的密文需要存储。SHA-1Blowfish cipher是比较有代表性的用于该目的的单向加密散列技术。当用户输入密码时,调用相同的Hash函数,并将生成的密文与已经存储的密文做比对。这个想法是,即使攻击者侵入了密码数据库,他们也需要破解那里存储的密码散列值才行。正如其名称所示,crypt_blowfish是在Blowfish算法的基础上实现的密码散列技术。

这个bug本身很简单,其修复方法在C程序员看来是显而易见的。在面向对象的程序设计系统中,需要把 BF_std.c: BF_std_set_key()中的
tmp |= *ptr;
改为:

tmp |= (unsigned char)*ptr;

基本上来说这是一个符号扩展的bug。对于那些不是C程序员的黑客,可能需要一点解释。当存储在*ptr中的值高位被置为1时,它将被视为一个负数。因此,在该值与tmp(一个无符号整型)做或运算之前,它会被提升到4字节并做符号扩展。例如一个byte值0x80会变成0xffffff80。正如人们所预料的那样,之后的或运算将会产生一个错误结果。

这个问题实际上是由John the Ripper(JtR)口令破译软件程序发现的。作为创建测试套件的一部分, "magnum"(万能)尝试去破解由一个库(并非crypt_blowfish)的散列函数产生的包含有单个非ASCII字符(£或0xa3)的口令。由于JtR和crypt_blowfish 共用相同的Blowfish加密算法实现,同时使用时测试会通过,但是算法其它的实现将产生正确的散列,从而会不匹配JtR所产生的散列。

JtR和crypt_blowfish的开发者Alexander Peslyak(同时也是Solar的设计者)分析了这个bug产生的影响并发现,一些口令组合通过散列运算会产生差异很小的相同值(例如"ab£" 产生的值为"£"),这将会使得口令破译变得简单。进一步的分析显示,在最高位被置1的字符前出现的一些字符在计算散列值时会被有效的忽略。这意味着一个比用户给出的密码更简单的密码也会被视为有效——这是对用户口令作用的一个重大削弱。

应该指出的是,Solar的设计者关于这个问题的细节说明及其产生的影响即将公布。他的CVE(通用漏洞披露)要求相当详尽,并且他为这个错误承担所有的责任。其他发现projects中存在安全漏洞的程序员也应该按照他的先例来处理类似情况。

JtR并没有什么实际问题,由于它可以更新算法,所以它可以正确破解高比特位设置为1的密码。此外,它可以继续使用老的算法来破解由于hash函数错误生成的密码。但是使用crypt_blowfish的应用就不可同日而语了。高位被置位可能相当少见——至少对于那些只服务ASCII用户的网站是这样,但是目前还没有简单的方法来判别存储的散列值是否有效。

对可能存在错误的密码散列值(包括现行的Openwall Linux (Owl), SUSE和 ALT Linux上的用crypt_blowfish算法产生散列值存储的密码数据库)的管理员来说,最安全的解决方案就是使现有的所有密码失效而后要求用户重新设置密码。这简直是逻辑噩梦。不过,这取决于如何简单、安全并且不需要通过现有密码鉴权就能使用户可以设置新密码。要求用户登陆以后改变现有密码是一种替代方案,不过这可能会给攻击者可乘之机。它同时为所有未登陆的用户保留原有密码不变。

攻击者利用这一漏洞登陆一个网站的风险相当小,但却是存在。如果一个网站的登陆过程容易受到暴力攻击,那么这个bug会使这个攻击变得容易,至少对于特定的密码类型是这样的。另一方面,如果密码数据库已经暴露出来,并且一些密码没有被破解(至少对于没有使用JtR程序的攻击者),这个信息可以给他们提供破译那些密码的方法。最终的分析结论是,这是一个可以被利用的,但并不会让管理员们陷入恐慌的漏洞。

令人惊讶的是这个bug在广泛被使用的库中存在了超过了13年!到目前为止,没有人用这种方式测试它,至少没有公开。这应该给那些使用固定版本软件(包括免费的和专有的)一些警示。自由软件(crypt_blowfish已经被置于公共领域,这可能在法律上有点模糊,但是这与自由软件的理念是一致的)有更多,更容易的机会来检查和测试代码,不过,只有实实在在的测试才是有效的。

毫无疑问,bugs依旧潜伏于我们每天所依赖的各种面向安全的库中,因此,定期地、系统地测试这些类库(还有那些没有用于安全用途的代码)可以帮助我们查出bugs。虽然超过10年才发现了这一bug,但值得指出的是,在此期间它可能已经被其他人发现。攻击者显然也在做自己的测试工作,不过他们的测试结果通常不会公布出来。可能和这里讨论的情况不一样,不过应该始终认识到,公开披露一个漏洞和它被发现之间是没有必然联系的(可能在被公开之前已经有人发现了)。

Topic: sohulinux

Brother Louie

周日开车的时候,从收音机里听到这首歌。

我靠,实在是太老了,太怀旧了。。下回去卡拉OK完全可以尝试

Topic: 音乐

新的连续内存分配器

A reworked contiguous memory allocator
By Jonathan Corbet
June 14, 2011

翻译:王鑫/李潇

关于分配大块儿连续物理内存的问题经常在 LWN 讨论。虚拟内存,由其性质决定了它总会将页面分散到整个系统;内核长时间运行后,可供分配的页面极少会出现一个挨一个的情况。多年来,内核开发者们处理这个问题的方式就是尽可能地避免对大范围连续内存分配的依赖。内核代码很少会试图分配超过两个的连续物理页面。

近来,关于大范围连续内存分配的需求越来越多。需求之一是超大页面数,尤其是transparent huge pages feature。另一个则是老树开新花了:硬件不能执行分散/收集DMA。任何只能对连续物理内存区域做DMA的设备(缺少I/O内存管理单元)都要求一个物理上连续的缓冲区来协同工作。这个要求通常是相对低端(stupid)的硬件的一个标志;你可以祈求这样的硬件随着时间越来越少。而我们所关注的是获得一定的能力的同时仍然保留着连续DMA要求的那些设备。比如,视频采集引擎,它能够采集完全高清的数据,然后在其上进行一系列的转换,但是它仍然会需要一个连续的缓冲区用来保存结果。高清视频的出现加剧了这个问题,那些物理连续的缓冲区现在比原来需要分配得更多,而且更难被分配了。

大概一年前,LWN 就开始关注解决这个问题的连续内存分配补丁。这个补丁集遵循着在启动时保留一大块内存的神圣而又庄严的传统,而这个的唯一目的就是为了满足大范围的分配需求。多年以来,这个技术一直被“bigphysarea”补丁所使用,或者简单地在启动内核时使用一个mem=的参数,用来留下一段未使用的物理内存。Android pmem driver也是从保留区域中分配大块内存的。这个方法当然有效,将近20年的经验足以证明它。保留内存的不利之处则在于它对其他任何想使用它的东西都是无效的;如果设备没用使用这块内存,它就简单地被闲置起来。这种内存的浪费在内核开发者和用户之间变得越来越不得心。

基于上述及更多的原因,CMA补丁从未被加入进去。尽管问题并没有被解决而且也没有开发者在其上工作,最新版的CMA补丁集看起来十分不同,虽然仍然有些问题需要解决,但是看起来本补丁集有较大的机会加入到主线中。

这个CMA分配器仍然能够同保留内存区域的方式一起工作,但那很明显不是想要的操作模式。相反,新的CMA试图维护当需要时能够创建连续大块内存的内存区域。为了那个目的,CMA依靠“migration type”机制被深度构建进内存管理代码中。

在每一个区段内,成块的页面被标记为被那些可移动的或可回收的页面使用。可移动的页面主要是那些缓存页或者匿名内存页,它们通过页表和page cache radix tree来访问。这些页的内容可以随着页表和树的更新而相应地被移动到其它地方。可回收页,则是在需要时返回给内核;它们像inode cache一样保存数据结构。不可移动页通常是那些内核拥有直接指针的页面,比如,通过kmalloc()申请的内存不能在不破坏任何东西的情况下被移动。

内存管理子系统试图将可活动页面保持在一起。如果要通过移动页面来获得掉一整块空闲内存,一个单独的固定页面就可破坏整个过程。通过将可活动页面分组,内核希望能不用遇到这个障碍就释放更多的页面,内存压缩代码目前就是依靠这些可活动页面才能工作。

CMA通过增加一个新的“CMA”迁移类型来延伸这个机制;它很像”可活动“类型,但有几点不一样。“CMA”类型比较棘手,内核不能改变被标志为CMA的页面的迁移类型。内存分配器不会从CMA区域分配固定页面,对于其他任何用途,只有当没有其他选择的时候才会分配CMA页面。如果一切顺利的话,被标志为CMA用途的内存区域只会包含可活动页面,并且有数量可观的空闲页面。

换句话说,被标志为CMA用途的内存对系统其余地方保持可用,只有一条限制,那就是它只包含可活动页面。当驱动需要一片连续的内存时,CMA分配器就在它的一个特定范围挤出足够的页面创建一个适当大小的连续缓冲区。如果在这里面的页面真正是可活动,分配器就提供驱动所需要的缓冲区。当缓冲区不再需要的时候,内存也可以被用作其他用途。

有人可能好奇为什么需要这样的机制,因为内存压缩机制就已经能够给transparent huge page创建大片物理上连续的块。那样的代码是可用的:我自己的 Linux 系统,在写这篇文章前,有大约25%被分配为大页面。这个问题的答案就是DMA缓冲区相对大页面有一些不同的要求。DMA缓冲区可能更大,例如,transparent huge page几乎在所有架构里都是2MB大小,而DMA缓冲区能有10M或者更多。如果底层的硬件足够“奇怪”的话,可能有必要将DMA缓冲区放在特定内存范围内,而CMA开发者 Marek Szyprowski看起来似乎就有这种“奇怪”硬件的需求。最终,2MB的大页面必须也有2MB的对齐,而对DMA缓冲区的对齐要求就宽松的多。CMA分配器能取得被请求数量的内存而不用过度担心严格的对齐要求。

CMA补丁集为建立内存区域和创建特定范围的“上下文”提供了一个函数集。有简单的cm_alloc()和cm_free()函数来获取和释放缓冲区。虽然如此,但预期设备驱动将不会直接调用CMA,相反,对CMA的意识将被固定在DMA支持函数里。当驱动调用函数如dma_alloc_coherent()时,CMA将自动被使用来满足要求。在大多数情况下,它应该能“正常工作”。

另外一个CMA的关注点是关于特定区域是如何设置的。目前的补丁期望在系统的board file里面做一些特殊的调用。这是一个很ARM式的方法。接下来的目的是去掉board file,这样就会发现其他东西。正如 Arnd Bergmann所指出的那样,将该信息移到设备树也不是一个选择。这其实是一个策略决策。Arnd正努力争取一些能在大部分系统工作的合理默认设置,其它一些少数系统将在后续被加进来。

最终的结果可能是,patch set至少得经过一个迭代才能进入主线。但CMA满足了以前从未遇到过的一个需求。这部分代码有潜在的可能性能够在减小对其余系统的影响的同时,让分配物理地址连续的内存变得更加可靠。看起来它似乎值得拥有。

Topic: sohulinux

PHP 的各个实现

挖个坑,备忘

  • Zend, 这个就不多说了
  • Quercus,原本是 resin 3 的一个特性,现在好似是作为一个独立项目运行... 看论坛上有人已经把它运行在 jetty 上了
  • P8,又一个运行在 JVM 上的 PHP 引擎,是一个 IBM 的项目,相比较 Quercus 而言,传说它比较好的支持了 PHP C 扩展。但这个项目的页面严重过时。另外它不是开源的
  • Phalanger,PHP on .NET,看起来正在积极的开发中,而且还有商业支持
  • PIPP,运行在 Parrot 上的 PHP,这个项目看起来已经死了,而且 Parrot 离被证明还很遥远
  • PHP 编译器,这个概念和前面的 Zend/JVM/Parrot 不太一样,着眼于直接编译出可执行代码,脱离 VM
    1. HipHop,地球人都知道
    2. phc
    3. Roadsend的Raven/rphp,基于 llvm
Topic: 技术

都不容易

暑假过了一个月,达达的心前所无比的野。不爱写作业,想尽办法偷懒

于是最近有那么段时间,几乎每天她妈都和达达发生剧烈冲突

白天我们上班后,奶奶和达达聊天

奶奶:......你说你妈妈容易吗?

达达:那我容易吗?

奶奶:你有什么不容易的

达达:我得让大人高兴

====

是啊,太不容易了

Topic: dada

blk-throttle: Throttle buffered WRITE in balance_dirty_pages()

http://lwn.net/Articles/446121/
From: Vivek Goyal

翻译:王鑫

Hi,

我一直在尝试寻找关于 blog IO controller cgroups 的以下两个问题的解决办法:
  • IO controller 的当前 throttling 逻辑无法限制buffered WRITES。它的实现是在设备上限制所有的 WRITEs,但到那时,buffered WRITE 已经丢失了提交者的上下文,并且大多数的IO进入到设备上的 flusher 线程的上下文中。因此当前并不支持对buffered write的限制。

  • 所有的WRITEs都在设备级上进行限制,这就很容易导致文件系统的串行。

举一个简单的例子,如果一个进程往cache中写入一些页面,然后运行fsync(),这个时候进程才开始被 throttled ,于是它会锁定整个文件系统。在ext4中,我注意到甚至一个简单的“ls”都不会再继续进行了。这个原因可以归结为文件系统并不关注cgroups和以顺序模式的文件系统日志这件导致串行这件事。

因此即使我们获得提交者的cgroup信息到设备并且在设备那里做限制,它仍然会导致文件系统的串行,这并不是一个好主意。

因此怎样去修正这个问题呢?貌似有以下两种办法:
  • 仍然在设备级上去做限制。让文件系统关注cgroups使得多个事务可以以并行的方式(每一个cgroup)同时前进,并且在cgroups之间并不存在那些导致文件系统串行的共享资源。

  • 当WRITEs进入cache时进行限制而不是直到设备才开始 throttle。比如类似balance_dirty_pages()这样的函数。直接IO仍然是在设备级上进行限制的。按照这种方式,关于限制,我们可以避免文件系统日志导致串行

但是这个方法的很重要的一点就是我们控制进入cache的IO速率而不是设备上的IO速率。按照那样的方法则可能会发生flusher过后会提交许多WRITEs到设备,并且我们将会在终端节点上看到许多周期性的IO spike。

因此这个方法可能会有一点帮助,但远远不是一个完整的解决方案。它主要能够帮助那些拥有许多IO资源和有效IO带宽但是希望控制资源分配给低优先级的客户。

方法1看起来很难去修正。在往文件系统写东西的时候,文件系统从不关注cgroups。因此我很怀疑我能够说服文件系统的设计者来改动基础的文件系统和日志记录部分的代码来使得文件系统关注cgroup。

因此我在本系列补丁中仅实现了方法2。方法2并不是一个最好的解决方案,但是它至少给了我们一些在buffered write上的控制能力,这总比一点都不给要好。Andrea Righi也曾经做过一个类似的补丁:
https://lkml.org/lkml/2011/2/28/115

这个补丁是关于bio和任务限制之间的交互的,因此我重做了它。

设计

IO控制器已经有跟踪一个group的IO速率的能力,并且当group超过一定速率时会把bio插入内部队列,并在随后将这些bio分发出去。

本补丁也引入了balance_dirty_pages_ratelimited_nr()中限制dirtying task的能力。现在所有除直接WRITES外的所有WRITEs在设备级上都不会受限制。如果一个dirtying task超过其配置的速率,它将被放入等待队列,当它可以dirty更多页面的时候才被唤醒。

没有新的接口被引入,直接IO和buffered IO都是使用通用IO速率限制。

How To

- Create a cgroup and limit it to 1MB/s for writes.

echo "8:16 1024000" > /cgroup/blk/test1/blkio.throttle.write_bps_device

- Launch dd thread in the cgroup

dd if=/dev/zero of=zerofile bs=4K count=1K

1024+0 records in
1024+0 records out
4194304 bytes (4.2 MB) copied, 4.00428 s, 1.0 MB/s

Any feedback is welcome.

Thanks

Vivek

Topic: sohulinux
订阅 RSS - 博客 | BT的花