Posts Tagged ‘linux’

[译文] Flushing out pdflush

February 9th, 2012

按:谨以此译文献给仍然挣扎在 CentOS 5/RHEL 5 上的同学们,RHEL 6/CentOS 6 已经包含这个改进了。

原作者:Goldwyn Rodrigues
原文时间:April 1, 2009
原文链接:http://lwn.net/Articles/326552/
译者:王旭( @gnawux, http://wangxu.me/blog/
翻译时间:2012年2月7-9日

在内核的页缓存(page cache)之中,存放着永久存储设备上的文件内容的内存副本。当程序把数据写入到页面之中,但还没写到磁盘上的时候,这些数据就放在缓存之中,这就是“脏页”。脏页的数量可以从 /proc/meminfo 中看到。每30秒,脏页都会被刷入(flush)磁盘。Pdflush 是一组负责将脏页刷入磁盘的内核线程,它或者是由显式的 sync() 调用出发,或者在页面被清出 page cache 时隐式地自动触发,具体情况包括,如果页面在内存中的时间过长,或者 page cache 中有过多的脏页(过多的界定由 /proc/sys/vm/dirty_ratio 确定)。

在任意给定的时间,系统中会有 2-8 个 pdflush 线程。pdflush 线程的数量由 page chche 的负载确定,如果一秒钟之内,没有空闲的 pdflush线程,但工作队列里还有很多工作要做,就会创建一个新的 pdflush 线程。另一方面,如果最后一个活跃的 pdflush 线程也已经睡了超过1秒了,那就会有一个 pdflush 线程被终止,知道只剩下了两个 pdflush 线程。当前的 pdflush 线程数可以通过 /proc/sys/vm/nr_pdflush_threads 查看。

很久以来,就有很多 pdflush 相关问题让它饱受诟病。Pdflush 线程是所有块设备共享的,但是,如果它们能专注于每一个磁臂的话,性能可能会更好一些。通过 backing_dev_info 结构的 BDI_pdflush 标志,可以避免 pdflush 线程的竞争,但是,互相影响还是会影响写回的性能。Pdflush的另一个问题是请求的饥饿问题。系统的每个队列中都可以有固定个数的I/O请求。如果超过了限制,所有应用的I/O请求都会被阻塞住,直到有新的空位出现。因为 pdflush 是为多个队列工作的,它不会阻塞在某一个队列上。这样,它会设置 wbc->nonblocking 写回信息标志。如果其他应用继续在设备上写入数据,pdflush 就无法分配出空位了。如果 pdflush 不断发现一个队列处于拥塞状态,就会导致这个队列的请求被饿死。

Jens Axboe 在一组 patch 中提出了一个新的方案,使用为每个块设备(backing device info, BDI)配置的 flusher 线程作为 pdflush 的替代品。与 pdflush 不同,BDI 专属的 flusher 线程专注于一个磁臂。在 BDI 刷写的情况下,当请求队列出现拥塞的时候,请求的分配会被阻塞住,避免饿死请求,提供了更好的公平性。

使用 pdflush,脏的 inode list 存储于文件系统的超级块。由于 per-BDI flusher 需要直到要写入的脏页属于那个块设备,所以,这个列表现在存储到了 BDI 里。这样,要刷入一个 superblock 上的所有脏 inode,就回导致刷入这个文件系统占用的所有后端设备上的脏 inode 列表。

与使用 pdflush 时类似,per-BDI 的写回是通过 writeback_control 数据结构控制的,写回程序从中知道写回什么、如何去做。这个结构中的重要字段包括:

  • sync_mode: 定义对于 inode 加锁的情况下,进行同步的方式。如果设置为 WB_SYNC_NONE,写回操作会跳过加锁的 inode,而如果设置为 WB_SYNC_ALL,则会等待加锁的 inode 被 unlock,再进行写回。
  • nr_to_write:要写的页的数量。这个值随着页面被写入而减少。
  • older_than_this:如果不为NULL,所有比这个字段中给出的 jiffies 值老的页面都会被刷入块设备。这个字段会优先于 nr_to_write。

bdi_writeback 结构保存了所有用于刷入脏页的信息:

struct bdi_writeback {
	struct backing_dev_info *bdi;
	unsigned int nr;
	struct task_struct	*task;
	wait_queue_head_t	wait;
	struct list_head	b_dirty;
	struct list_head	b_io;
	struct list_head	b_more_io;

	unsigned long		nr_pages;
	struct super_block	*sb;
};

bdi_writeback结构是在设备使用 bdi_register() 进行注册的时候初始化的。结构的各个字段的含义如下:

  • bdi: 和本结构实例相关联的 backing_device_info,
  • task: 指向缺省flusher线程的指针,这个线程用于启动进行刷写工作的线程,
  • wait: 用于同步flusher线程的等待队列,
  • b_dirty: 本 BDI 上面,需要刷入块设备的所有脏 inode 的 list,
  • b_io: 要进行 I/O 的 inodes ,
  • b_more_io: 更多的要进行 I/O 的 inodes ;所有要刷入的 inode 都先被插入到这个队列中来,之后再移送到 b_io,
  • nr_pages: 要刷入的页的总数,以及
  • sb: 指向当前 BDI 上的文件系统的超级块的指针。

nr_pages 和 sb 是异步传送给 BDI 刷写线程的参数,并且在 bdi_writeback 的生命周期中是可能发生变化的。这是因为有些设备上会有多个文件系统,也就会有多个超级块。当一个设备上有多个超级块的时候,sync 操作可以针对设备上的某一个特定的文件系统。

bdi_writeback_task 函数会周期性发起 wb_do_writeback(wb) 调用,调用周期为 dirty_writeback_interval,缺省值是5秒。如果5分钟内都没有页面被写入,flusher 线程就回退出(计时精度为 dirty_writeback_interval)。(退出)之后如果又需要工作了,那么就会由缺省写回线程来启动一个新的 flusher 线程。

写回的flush有两种工作方式:

  • pdflush方式:由显式的协会请求触发,比如 sync 一个超级块的所有 inode 页面。这时会以超级块的信息和要刷入的页面数量为参数调用 wb_start_writeback()。这个函数会去获取与此 BDI 相关联的 bdi_writeback 结构。如果获取成功的话,会将 superblock 指针和要刷入的页的数量写入 bdi_writeback 结构,并唤醒 flusher 线程,为该超级块进行实际的写操作。这个操作和 pdflush 的写入操作有所不同:pdflush 会根据写的路径来获取设备,阻塞住其他进城的写操作。
  • kupdated 方式:如果没有显式的写回请求,写回线程会周期性地刷入脏数据。当一个 BDI 的一个 inode 的页面第一次变脏的时候,会将 dirtying-time 记入 inode 的地址空间中。当周期性的写回代码检查到这个超级块的 inode 列表的时候,就回写回比某一时间更早变脏的 inode。这一操作的周期是 dirty_writeback_interval,缺省是5秒钟。

第一轮的讨论之后,Jens 根据 Andrew Morton 的建议,添加了每个设备有多个 flusher 线程的支持。Dave Chinner 建议,文件系统可能会希望每个分配组有一个 flusher 线程。在随后的(第二轮)补丁中,Jens 在 superblock 中添加了一个新的接口,来通过一个 inode 获取相关联的 bdi_writeback 结构:

struct bdi_writeback *(*inode_get_wb) (struct inode *);

如果 inode_get_wb 为空,就会返回 BDI 缺省的 bdi_writeback 结构,这就意味着这个 BDI 只有一个 bdi_writeback 线程。每个 BDI 可以启动的最大线程数为 32。

Jens 对一块 SATA 硬盘使用 Flexible File System Benchmark (ffsb) 进行的测试显示,可以获得 8% 的性能提升。通过 vmstat 观察,与未打过补丁的内核相比,文件操作的分布更加平滑 ,缓冲区的写回呈现出均匀分布。而对于一个10块硬盘的 btrfs 文件系统,per-BDI 刷写可以获得 25% 的提速。这组代码位于 Jens 的块设备层 git tree  (git://git.kernel.dk/linux-2.6-block.git)  的 writeback 分支。目前,第二轮讨论还没有新的意见出现,但 per-BDI flusher 线程还不足以进入 2.6.30 内核。

致谢:感谢 Jens Axboe 审阅本文并对这组补丁的一些内容进行了解释。【译文完】

[译文]Ext4新进展:bigalloc, inline data, 和元数据校验和

February 4th, 2012

原文:http://lwn.net/Articles/469805/
原作者:Jonathan Corbet
原文发布时间:November 29, 2011
译者:王旭 ( @gnawux ;  http://wangxu.me/blog/ )
翻译时间:2012年2月3日

ext4是一个刚刚发布一两年的文件系统。不过,这个坚实稳定的系统是基于一个很古老的设计演化而来的。对于一些被作为“下一代文件系统”开发的 FS,比如 btrfs,本文要提到的一些特性可能都已经具备了。然而,btrfs这样的文件系统还需要相当长的时间,才能在更广泛的用户群中获得足够的信心,同时,日益增长的 ext4 用户对这些特性同样心仪已久。近来提交的一些补丁就让我们看到,虽然 ext4 在很久以前就已经进入一个相对稳定的阶段了,但新特性的开发也并未停止。

Bigalloc

在 Linux 早期,磁盘的大小还是MB级的,文件系统的块大小也只是 1KB 到 4KB。而在本文写作的时候,TB级的硬盘虽然在最近涨了一点价,但无碍一个事实——硬盘已经变大太多了,存储在上面的文件也是如此。但 ext4 文件系统仍然以 4KB 为单位来管理数据。其结果就是要管理的块数太多了,相关联的位图大小必然随之增长,管理这些块的开销也就极具增大。

在内核中增加文件系统的块大小会对内存管理、page cache 等产生深远影响,因此是件很恐怖的工作。所以大家都不愿意一下子触及这么多地方,但这并不能阻止文件系统被放在越来越大的磁盘上。在 3.2 内核中,ext4 将可以解决这个问题。“bigalloc”补丁给文件系统引入了一个“块簇(block cluster)”的概念,这样,在一个更大的块组中进行分配时,将一次分配一个块簇而不是一个单独的块。在内核中,这些更大的块和原始的4KB块的映射关系由文件系统负责维护。

簇的大小由管理员在创建文件系统时确定(使用 e2fsprogs 的一个开发版本),不过这个值必须是 2 的整数次幂。在很多情况下,64KB 是个合适的值,对于那些只存放大文件的文件系统,1MB 的簇大小可能是更佳选择。必须指出的是,如果文件系统专用于存放小文件,那么指定一个过大的簇大小回造成很多空间浪费。

使用簇可以减少块位图和其他管理用数据结构的开销。但是,根据 Ted Ts’o 在 7 月份给出的数据。因为这个特性可以降低磁盘的碎片化,对文件IO的性能同样有改进。这个特性预计会成为 3.2 内核(以及 e2fsprogs 1.42)对很多用户的一个杀手级特性。

inline data

inode 是文件系统中用于描述一个文件的数据结构。对于大多数文件系统而言,有两类 inode:文件系统无关的内核数据结构(struct inode),以及文件系统相关的 on-disk 版本。常规地说,如果内核没有一份 inode 的副本的话,就根本无法操作一个文件。所以,本质上说,inode 是很多 block I/O 的关键入口点。

在 ext4 文件系统中,磁盘上的 inode 尺寸可以在文件系统创建时指定,缺省是 256 字节。不过,磁盘数据结构(struct ext4_inode) 只需要大概一般的空间。ext4_inode 结构之后剩下的空间通常用于存储扩展属性。比如 SELinux label 就存放在这里。在没大量使用扩展属性的系统中,磁盘 inode 结构的空余空间就直接浪费掉了。

同时,文件数据的空间分配是以文件系统块为单位的,与 inode 彼此独立。如果一个文件非常小(即使在现在的文件系统中,还是有很多小文件),用于存放这个文件的块就浪费了很多空间。如果文件系统使用了上面提到的块簇,那么浪费的空间还会更多,这里,用户可能就会开始抱怨了。

马涛(@淘伯瑜)同学的 ext4 inline data 补丁将会改变这一局面。这个想法非常简单:很小的数据可以直接存放在 inode 之间的空余空间里,根本无需单独分配数据块。对于使用 256个字节的 inode 的文件系统,全部空余空间将会被用于存放这些小文件。如果文件系统使用更大的 inode,只有一半的剩余空间会用于存储文件,剩下的空间留给后面可能要添加的扩展属性,否则的话,这些扩展属性就不得不存放在 inode 之外了。

涛哥提到,在使用了这个补丁的情况下,用于存放内核源码的空间会减少大约 1%,而 /usr 会减少大约 3%。当启用簇之后,节省的空间应该会更多,但这也不能保证对所有情况都能减少。仍然有些细节问题没有完全完成——包括 e2fsck 支持以及扩展属性存放在 inode 之外带来的开销——所以,这个特性最早要在 3.4 kernel 中才会出现。

元数据校验和

存储设备并不总是像我们期望的那样可靠的,由于硬件原因造成的数据损坏案例屡见不鲜。正因为如此,关心数据安全的人们使用了 RAID 这样的技术,或者像 Btrfs 这样的文件系统可以保存数据和元数据的校验和,以确保内容不被硬件弄丢。不过,ext4 文件系统没有这一能力。

Darrick Wong 的校验和补丁并没有解决全部问题。实际上,它似乎进一步印证了那个老笑话——文件系统开发者并不真的关心他们存储数据的正确性,只要文件系统的元数据没错就行了。这组补丁通过给 ext4 文件系统的各个数据结构加上校验和,包括 superblock、bitmap、inode、dir index、extent tree 等,并在读取时检验校验和,以保证元数据的正确性。校验和失败可能导致文件系统失败,如果这发生在一个挂载着的文件系统上,会把它变为只读,并在系统日志中输出一些相关信息。

Darrick并未提及任何给用户数据添加校验和的计划。给数据添加校验会是一个更宏大的工程——为已有的元数据数据结构添加一个校验字段相对简单,但要存储数据块的校验和就得给文件系统增加全新的数据结构了。而且,全数据校验的性能损失也会更高。所以,尽管未来可能有人会来介入这个问题,但迄今为止还没有这个动向。

即使只是元数据的校验和,对文件系统的改变仍然是很大的,不过相当一部分工作是属于 e2fsprogs 的。特别的,e2fsck 将具有检查元数据校验和的功能,并在某些校验和出错时进行修复。校验和可以在 mke2fs 时打开,或是通过 tune2fs 开启。总的说,这是个很大的工作,但确实可以帮助用户增加对文件系统结构的信心。根据 Darrick 的介绍,计算和检验校验和的开销在大部分情况下是可以忽略不计的。这个特性目前还没有收到很多反馈,或许已经接近被接纳进内核,但还不清楚什么时候会进来。

2011年最后一次版聚小记

December 12th, 2011

感谢彭涛(bergwolf)、李凯(郁白)、朱延海和 Coly 的到场,这次版聚虽然只有一个主话题,但是由于有这么多到场者的深度参与,变得很有趣、很有收获。特别感谢 bergwolf 熬夜准备片子,还有李凯为每个环节配上小故事。

按:之前由于各种苦逼原因,版聚一度中断两个月之久,在此危急存亡的时刻,hzmangel 同学挺身而出组织了这次盛会,我很荣幸地帮助预定了盛大创新院(北京)的会议室,bergwolf 贡献了 aio 的 topic,至此本年度12月版聚得以正常举行。

到场同学

具体到场同学就不一一点名了,大家可以看邮件列表,值得一提的是,这些同学有千丝万缕的联系:

  • 有四个人是互为同学来的
  • 有两个人是同一个组的
  • 有两个人是同事
  • 有一个人和上面同一个组的人不是同一个组的,和上面两个同事的五个同事或前同事是前同事
  • 有一个人和上面四个同学中的一个是同学

同学们,你们明白了么?

序曲:async/sync vs. blocking/non-blocking

这个话题被认为上次在 SNDA 会议室已经搞清楚了,可实际情况是——

当 Coly 出现后,问题再次变得混乱起来,

好吧,我们承认,这两对概念的两两组合足以让人抓狂,结论是:大家要记好了,名字叫 non-blocking 的就是 non-blocking,名字叫 async 的就是 async,嗯。

这个争论的价值是:

  • Coly: 对于用户程序,不论是否有 NON_BLOCKING 标志,都必须检查 read 的返回值是否达到了请求值,也就是说,即使 read 返回了 >0 的值,也可能会小于请求值,如果没有,需要循环请求,直到全部读完。
  • Bergwolf: 对于文件系统的实现者,对于 buffered IO,在没有信号中断的情况下,read 请求如果不失败,返回值不应该小于请求值。如果小于请求,应该视为一个 Bug。

感谢 coly 和 bergwolf 从不同角度对这个问题的阐述。

插曲:郁白的DIO故事

事实上,本次版聚是由李凯同学来主持的,每一段他都有一个小故事。对于这里,郁白同学介绍——

他曾经使用 DIO 模拟 append,这时,如果超出 512B 的块大小,需要补齐再 truncate 回来,有时会发生 EIO,求解答

经过 coly、bergwolf、朱延海等同学的合议,认为这个问题有可能是 journal 的 bug,因为郁白同学仗着自己使用了很好的 raid 卡,对 journal 区域进行了疯狂的操作,在一次 append 中,最差情况可能有 5 次 io,而且由于他经常 sync,还丧失了合并日志操作的机会,在这种极端情况下,可能会触发 journal 的某个深藏的 bug。

正文上半场:POSIX AIO

简单地说,POSIX AIO ( aio(7) )是由 glibc 使用 pthread 在用户空间实现的,由于实现的比较粗糙,没有线程池等机制,这一实现的性能比较低劣——说到这里,有几位同学灰心地苦笑了一下。

本日出镜最高的郁白同学介绍——Linux 中的 POSIX AIO 实现没有线程池,而且有可能有锁冲突,还可能有其他bug,所以导致性能低下,大约为 pread/pwrite 的 1/3;如果自己妥善地实现一个用户空间 AIO 的话,性能和同步 IO 的性能应该是基本一致的,当然,上下文切换可能是不可避免的。

朱延海这里有一个想法,是否可以用非阻塞读写和 select/epoll 来做一个更好的 AIO,殷宇辉同学表示 libeio 可能已经这么做了。

正文下半场:Native AIO

kernel 态的 Native AIO 性能上没有什么问题,但是,它有一些限制——

  • 只支持 AIO-DIO
  • 不支持 fsync/fdatasync
  • 不支持 socket/pipe

并且,bergwolf 表示,据他前一晚上写片子时看代码,ext4 的 aio 似乎没有用上,coly 和朱延海对此不太相信,大家表示后面会再继续研究一下。

郁白同学此时又有提问:有时 get events 的时候 get 不到,这时内存中用于 io 的 buffer 是否可以安全释放?经过一段讨论,结论大致是这样的:

  • 首先,IO 用的 page 是 lock 住的,实际不会被释放掉;
  • 其次,libc 中,free 并不一定会还给内核,而可能会重复给其他进程用;
  • 这时,如果内存我们还给 libc,libc 又分给其他 malloc 用,在 IO 完成时可能回冲掉这块内存,从而造成了后一个 malloc 不安全

所以,这时的内存释放和管理需要谨慎。

总结 by 郁白

作为每个环节都有话说的李凯同学,这时给了一个总结:

他比较喜欢用户态的实现,如果有个靠谱的用户空间库,他不太喜欢使用 native 的实现。

版聚笔记到此为止,linuxfb 2012 见。

[译文] SCSI Target 之双城记

November 18th, 2011
作者:Goldwyn Rodrigues
原文发布日期:January 22, 2011
来源:http://lwn.net/Articles/424004/
译者:王旭( http://wangxu.me , @gnawux )
翻译时间:2011年11月17日

按:上次翻译 LWN 的文章似乎还是 两年前翻译空指针的乐趣的事呢,时间好快,这次来深圳高交会看展台,晚上无聊,就翻译了这个。作为这个故事的结局,LIO已经在 2.6.38 进入 kernel 了。

2010年底,LIO 项目获选成为新的内核态的 SCSI target,取代原有的用户态的 STGT 项目。当时有两个主要的竞争项目(LIO和SCST),都在努力将代码并入主线内核。本文将比较着两个项目,并尽力描述他们都提供了什么东西。

什么是 SCSI Target?

SCSI 子系统使用了一种客户机-服务器(C/S)模型。通常,一台计算机是这个模型中的客户机,称为 initiator(发起者),想 target (目标)发起块操作请求,这个 target 通常是一个存储设备。SCSI Target 子系统可以让一台计算机作为一台 SCSI 存储设备来工作,响应其他 SCSI initiator 节点的存储请求。这样就可以定制 SCSI 存储设备,并让存储设备工作得更加“智能”了。

一个智能 SCSI Target 的例子是Data Domain的在线备份设备,它具有数据排重的功能,可以节约空间。这个设备从功能上说是个 SCSI target,但它实际是一台智能的计算机,它只存储那些还没有的数据块,对于已经存在的数据,只是增加引用计数,这样只写入那些上次备份之后有变动的块。而在 SCSI 连接的另一边,initiator 看到的设备就是一个普通的、共享的 SCSI 存储设备,只要使用任意的备份软件,将备份写向这个 target就行了。

最常见的 SCSI target 子系统的实现是 iSCSI 服务器,它使用标准的 TCP/IP 来封装 SCSI 指令,通过网络来提供一个 SCSI 设备。大多数 SCSI target 项目在最初都会先支持 iSCSI 协议。这事因为 iSCSI initiator 和 iSCSI target 之间只需要一个网络连接,差不多所有计算机都可以使用,对它的支持不需要任何特殊硬件。不过,大部分的 SCSI target 还能支持已有的 initiator 卡,所以,如果你又一个光纤通道、SAS 或并行 SCSI 卡,可能某个 SCSI target 项目可以支持这些特定设备的 SCSI 总线。

当前状态

当前 Linux 内核的 SCSI 子系统使用 STGT 来实现 SCSI target 功能;STGT 是在 2006 年末,由 Fujita Tomonori 引入的。它在内核中有一个库,来配合内核中的 target 驱动工作。而所有的 target 处理都在用户空间完成,这可能回带来一些性能瓶颈。

有两个还没有并入内核的 SCSI target 实现尅考虑用来替换 STGT:LIO SCST。SCST 至少在2008年就试图推入 Linux 内核。当时认为 STGT 项目海可以为内核服务稍长一段时间。但随着时间的推移,STGT 的设计局限被发现,并且有了一个可用的替换方案。替换 SCSI target 子系统的主要条件是由 James Bottomley 确定的,他是 SCSI 的维护者,条件如下:

  1. 它将更换掉已有的 STGT,因为只能有一个 SCSI target 基础设施。
  2. 要使用现代的、基于 sysfs 的控制与配置方式。
  3. 代码要被仔细审查,确定足够干净、可以进入内核。

第一个条件被证实太过于严苛了,会不可避免地破坏整个 ABI。所以,当前的目标变成了寻找一种方法,来让 STGT 用户平滑地过渡到新接口上来。

LIO 替代 STGT 的项目开始于 2010 年的 Linux 存储与文件系统峰会(LSF 2010)。Cristoph Hellwig 志愿来审阅并清理代码,他尽力将代码缩减到一万行以内,使之可以被并入内核。

对比

两个项目都在他们的官方网站(LIO 和 SCST)上提供了他们的特性对比图表。不过,在探讨它们的不同之前,先来看一下相似性吧。两个项目都实现了一个内核态的 SCSI target 核心。他们都提供了类似 loop device 的本地 SCSI target,这让使用他们的 target 创建虚拟设备变得很方便。两个项目都支持 iSCSI,这是他们的项目的最初的也是最主要的动机。

两个项目的后端存储管理都可以在内核空间或是用户控件进行。后端存储管理器让 target 的管理员可以控制设备如何输出服务给 initiator。比如,pass-through 后端允许将一个 SCSI 硬件直接提供给用户,而不屏蔽掉这个设备的任何细节;而 virtual-disk 后端则允许将一个文件作为虚拟磁盘来输出给 initiator。

两个项目都支持永久性预留(Persistent Reservation, PR);这是一个用于高可用集群中的存储设备的 I/O 隔离与存储设备故障切换、接管的特性。通过使用 PR 命令,initiator 可以在一个 target 上建立、抢占、查询、重置预留策略。在故障接管过程中,新的虚拟资源可以重置老的虚拟资源的预留策略,从而让故障切换更快、更容易地进行。

SCST

SCSI target 子系统的主要用户是提供存储解决方案的存储公司。大部分这些存储解决方案都提供了即插即用的设备,可以只进行很少的配置,甚至是无需配置,就被加入到一个存储网络。SCST 拥有更广泛的用户群,这可能是因为它们支持更多的传输方式。

SCST 支持 Qlogic 和 Emulex 的光纤通道卡,而 LIO 目前只支持 Qlogic 的 target 驱动,并且这个驱动也还在 beta 测试截断。SCST 支持 SCSI RDMA 协议(SRP),并宣称对于以太网传输的光纤通道协议(FCoE)、LSI 的并行 SCSI 光纤通道以及串行 SCSI(SAS)等协议的的开发也处于领先地位。目前,它已经对 IBM pSeries 的虚拟 SCSI 提供了支持。目前,Scalable Informatics、Storewize、Open-e 等公司都基于 SCST target 开发了它们的即插即用设备。

SCST 可以使用异步事件通知(AEN)来通告会话状态的变更。AEN 是一个 SCSI target 用来向 initiator 进行 target 端的事件告知的协议特性,即使在没有服务请求的时候也可以进行。于是 initiator 就可以在 target 端发生事件时,如设备插入、移除、调整尺寸或更换介质时,可以得到通知。这让 initiator 可以以即插即用的方式看到 target 的变化。

SCST 的开发者声称,它们的设计在健壮性和安全性方面更加符合 SCSI 标准。SCSI 协议要求,如果一个 initiator 要清除另一个 initiator 的预留资源时,预留者必须要得到清除通知,否则,多个 initiator 都可能来改变预留数据,就可能会破坏数据。SCST 可以实现安全的预留、释放操作,避免类似事情发生。

依照 SCSI 协议,initiator 和 target 可以协商决定传输尺寸。一个 initiator 端错误的传输尺寸通信可能会导致 target 设备端的锁死或是崩溃。SCST 的安全保障机制可以在传输尺寸或方向出错时避免这个问题。他们的代码中具有良好的内存管理策略来避免内存耗尽的情况。还可以限制介入 target 的 initiator 的数量,避免过多连接占用资源。SCST 还支持每个 portal 的可见性管理,也就是说,可以让一个 target 只对一组 initiator 可见。

LIO

LIO 项目最初是以 iSCSI 作为核心目标的,创建了一个支持 iSCSI 的通用 SCSI target 子系统。简单性是项目的一个重要设计目标,因此,LIO 也更容易理解。除此之外,LIO 的开发者表现得更乐于和内核开发者合作,正如 James 对 SCST 的维护者 Vladislav Bolkhovitin 所指出的:

来,让我们把事情说得简单一点:在这个社区里,不是让你直接把菜上到桌上就行了,你需要加入到这个社区当中来,称为 linux 内核社区的一部分。更广泛的社区焦炉是开源项目成功的必要条件。你曾经有过这样的机会了:我们在其他地方已经使用了 sysfs,但在 STGT 这里,你就说了一句——这事我们的接口,用它好了。而 LIO 则问了他们所需要的东西,并设法来使用 sysfs 接口。事已至此,你为什么还会对 STGT 的人更倾向于 LIO 而表示大惊小怪呢?

LIO 项目还提供了一些 SCST 没有或刚刚开始开发的特性。比如,LIO 支持非对称逻辑卷分配(ALUA)。ALUA 允许 target 管理员来管理 target 的访问状态和路径属性。这让多路径路由机制可以选择最好的路径,从而根据 target 的访问状态,优化带宽的使用。换句话说,在多路径环境下,target 管理员可以通过改变访问状态来调整 initiator 的路径。

LIO 海支持管理信息数据库(MIB),会让管理 SCSI 设备更简单。SCSI target 设备可以按照 RFC4455 SCSI MIB 的描述方式来输出管理信息,这些信息会被 SNMP agent 收集起来。这个特性扩展了 iSCSI 设备,在管理有很多 SCSI 的存储网络时好处会更加明显。

iSCSI 连接的错误可能会发生在三个层面上:会话、校验或是连接层。错误恢复工作也可以在这三个层面开始进行,这样就可以在当前的层面开始进行恢复,不会让错误到达下一个层面。错误恢复首先是检查断开的连接。在这种情况下,iSCSI initiator 驱动会主动建立新的到 target 的 TCP 连接它会告诉 target,SCSI 指令路径已经变到新的连接上了。这样 target 就可以在新的连接上处理 SCSI 命令了。这时,上层的 SCSI 驱动对新的连接已经建立、控制信息已经通过新连接传输的事还是毫无知觉的。iSCSI 会话在这期间会保持正常,不会重新变换状态。LIO 支持的最大错误恢复级别(ERL)为2,这就是说,它可以在会话、校验或连接层进行错误恢复。而SCST 支持的 ERL 为 0,也就是说,它智能恢复会话级别的错误,所有连接层面的错误都会转到 SCSI 驱动层面来处理。

LIO 还支持“会话多连接”(MC/S)。MC/S 让 initiator 可以和 target 在一条或多条物理路径上建立多条连接。这样,在一条路径发生错误的时候,已经建立好的会话可以不中断会话,直接使用其他的路径。MC/S 还可以用来进行所有连接之间的负载均衡。这种情况下,会在所有通信路径上保持会话命令的顺序性。

LIO 还宣称,他们的代码被用于了很多设备之中,虽然他们的用户看起来和 SCST 的差不多。

没有性能对比的对比不是个完整的对比。SCST 的开发者经常会放出他们的性能数据。但是,所有数据都是和 STGT 进行的对比。SCST 的对比页面说,他们的性能好于 LIO,但是是根据代码研究而非真实世界测试的结果。SCST 指责 LIO 没有发布数据,(在我的印象里)确实没有性能数据来在两者之间进行直接对比。

不过最后,决定已经做出了,虽然有一点反对的声音。现在的任务就是把所有 LIO 没有但有用的特性从 SCST 移植到 LIO 来。尽管这个决定有些争议,但这俨然又是一次试图把不能和内核社区合作的代码并入内核的失败尝试。

 

一个自动搭建ipip隧道的脚本

March 28th, 2011

场景是这样的,两台机器A和B,通过缺省路由互相可达;希望A通过B的连接出去;A的地址为动态分配,且A可能的interface不缺定,因此,上来先给点先决条件:

 

#!/bin/bash

 

default_dev=”wlan0″

default_gw=”192.168.12.1″

flag_nogw=”false”

 

local_ip=192.168.12.111

thost_ip=192.168.32.214

tnet_cidr=”192.168.32.0/21″

 

local_tun_addr=”172.16.1.1″

remote_tun_addr=”172.16.1.254″

tun_dev=”tun9″

tun_cidr=”172.16.0.0/16″

 

然后,想办法获取缺省路由的接口和网关地址,当然,不一定所有的缺省路由都有网关地址

 

# get default gw and local ip address 

route -n | while read dst gw msk flag metric ref use iface

do 

        if [ "$dst" = "0.0.0.0" -a "$msk" = "0.0.0.0" ]

        then    

                default_dev=$iface

                if [ "$flag" = "UG" ]

                then    

                        default_gw=$gw

                else    

                        flag_nogw=”true”

                fi      

        fi      

done

之后判断一下连在缺省接口上的IP地址
local_ip=$(ifconfig $default_dev | grep “inet addr”|sed -ne ‘s/.*inet addr:\([.0-9]\+\).*/\1/p’)
然后在远程主机上启动隧道、配置路由,并设置NAT:
ssh ${thost_ip} iptunnel add ${tun_dev} mode ipip remote $local_ip local ${thost_ip}
ssh ${thost_ip} ifconfig ${tun_dev} ${remote_tun_addr}
ssh ${thost_ip} route add -net ${tun_cidr} dev ${tun_dev}
ssh ${thost_ip} iptables -t nat -A POSTROUTING -s ${local_tun_addr} -j MASQUERADE
接下来设置本机上的隧道和路由:
#setup tunnel on local machine
iptunnel add ${tun_dev} mode ipip remote ${thost_ip} local ${local_ip}
ifconfig ${tun_dev} ${local_tun_addr}
route add -net ${tun_cidr} dev ${tun_dev}
最后,改缺省路由
#setup default route rule
if [ "${flag_nogw}" = "false" ]
then
        route add -net ${tnet_cidr} gw ${default_gw}
        route del default gw ${default_gw}
else
        route add -net ${tnet_cidr} dev ${default_dev}
        route del default dev ${default_dev}
fi
route add default gw ${remote_tun_addr}
完毕。

CentOS/RHEL 5.4 BCM5709网卡问题

December 13th, 2010

前不久我们的一批使用 Broadcom NetXtreme II BCM5709 千兆网卡的 CentOS 5.4 机器的网卡在大负载下频频挂掉,无法ping通任何其他机器,但可以ping通自己,只要重启网卡即可恢复,实在让人费解。

Google了一下,发现此版本的 bnx2 驱动缺省使用了 MSI-X,但在处理中断时可能会出现问题,具体影响的版本如下:

# uname -r
2.6.18-164.6.1.el5
# modinfo bnx2 |grep “^version”
version:        1.9.3

Red Hat的KB/Bugzilla里是这么记录的

in certain circumstances, under heavy load, certain network interface cards using the bnx2 driver and configured to use MSI-X, could stop processing interrupts and then network connectivity would cease. (BZ#587799)

嗯,解决方法,很简单,在/etc/modprobe.d/目录中添加一个文件,比如叫bnx2,设置一下模块参数:

# cat /etc/modprobe.d/bnx2
# This is believed could solve the network freezing problem
# RHKB: in certain circumstances, under heavy load, certain
# network interface cards using the bnx2 driver and configured
# to use MSI-X, could stop processing interrupts and then
# network connectivity would cease. (BZ#587799)

options bnx2 disable_msi=1

如果不重启机器的话,就重启一下模块

# modprobe –r bnx2
# modprobe bnx2

然后就OK了。

LinuxFB版聚总结

April 28th, 2010

2010年4月25日,linuxfb(北邮真情流露Linux版)在老据点之一——北邮教三某实验室的会议室举行了一月一次的版聚。由于聪明的同学们都看了天气预报没来,追星的同学都因为Coly同学缺席没来,版聚史无前例的只有11人出席,不过,还是一如既往的深入、一如既往的愉快。在此感谢李东阳、彭涛和Casparant同学的分享。参加的同学在Google Wave里有记录,搜索“linuxfb with:public”就能找到了,这里不再赘述,仅仅提一下几位突出贡献同学:

  • bergwolf,也就是彭涛同学,每次在自我介绍时都会一如既往地将戒指从无名指挪到中指,这次贡献了一个很时髦的话题,一会再介绍,希望下次再聚会的时候不再需要这么挪戒指了——呃,我不是说要他提前挪好哈,大家明白吧。
  • lidongyang,李东阳每次来都给我留下深刻印象,尤其这次,带来了第一个精彩话题,当然,一会还是会介绍到的。
  • 上面两位同学各带来一位围观者,不同的是,含蓄的东阳不想让在他组实习的mm来,而bergwolf则邀请来一位师妹,不知道这两位可爱的mm是不是以后还会来参加啊,呵呵
  • jerry/文捷,还有saka,都是来参加版聚新同学,热烈欢迎他们,saka让我们想起了久违的LeoVirgo,啥时候能再聚聚啊
  • bunbun是版聚的老面孔了,搞技术的女孩,呵呵,redsand后继有人啊,话说如果redsand下次带宝宝来的话,我也带我家儿子来,哈哈。
  • gmoto,linuxfb五年版聚史中的第一偶像派的帅哥,这次也来了,可惜没有topic和众多的男女fans
  • hzmalgel,版聚的元老,这次也一如既往的拒绝承认有女朋友,一样的活跃,而且参与了中间的caspar的VPN环节,试用了cooler提供的VPN账号,当然,没成功
  • casparant,本次版聚的多面手,测试了投影仪,担任了摄影师,还在第二个话题中介绍了多种翻墙技巧。

李东阳这次介绍了一个ocfs2的一个bug,大概是这样的,fsstress的truncate会出错,内存中和磁盘上的元数据不一致,东阳同学在VFS的direct write位置定位了这个问题。背景是这样的:OCFS2的Direct Write不允许改变元数据,以获得更好的并发性能。但如果发现有O_DIRECT而不能directio,就送回VFS去做buffered io,可是,VFS的aio还是会检查 o_direct,回到 ocfs2_direct….,最后,该函数只查看 offset,不判断是否超出inode的范围,于是就出现了问题。最终的修改比较直接,就是要确定不要回到direct,只要确定进aio,就一定进aio,这样就不会出问题了。曲折的debug故事一直是我们比较喜欢的话题,非常有趣。

最后,bergwolf介绍了ATA的新指令TRIM,用于宣称某个块已经没有用了,可以被删除了,希望来帮助SSD更主动地垃圾回收,从而提升性能。2.6.33的内核已经支持了TRIM,btrfs和ext4也会使用TRIM。但是TRIM指令的设计师非常匪夷所思的,不能进入queue,类似barrier,这样,需要等前面的指令执行完才能执行TRIM,而TRIM完成之后才能有新的指令进入queue,一次的时延有上百毫秒,如果大量使用这个命令的话,反而会影响性能。结论是——这个命令暂时没啥好处……

总之,感谢讲话题的三位同学:lidongyang,bergwolf,casparant,也感谢永远的组织者,colyli和hzmangel,当然,我也会一如既往的记下去。

一行的日志统计计算脚本

January 20th, 2010

accu=0;sed -ne ‘s/.*bytesIn=\”\([0-9]*\)\”\/>/\1/p’ stage_3.xml |while read num;do cur=$(($num-$accu));accu=$num; echo $(($cur/20/1024/1024));done

记在这里了,先不解释了。

发放《Debian标准教程》示例源代码

December 21st, 2009

早有此意,但今天做发放这个动作主要是源于内疚,由于我自己对出版过程关注不够,有很多示例的排版有严重问题,给阅读带来极大不便,因此,这里给出示例全部代码,并且,今后会进一步给出更多的信息。

代码放在Google Code

https://code.google.com/p/unleashed-debian/

在此向大家致歉。

Moblin 2.1体验&小hack

November 30th, 2009

大家好,我现在是从工作在eeepc 1000he 的 moblin 2.1上面发出的本帖。每次见过陈绪之后,回来都会玩玩 moblin,说实话,我很喜欢这个界面:)

另外,修改 mojito 的 services/twitter/twitter.c 第 515 行代码,重新 rpmbuild 这个包,就可以使用自定义 api 了,本来还准备回一个 patch 的,不过,我这里是 http 的 api,原始代码是 https 的直连 twitter,不知道能不能被接受。

先上图片吧,首页可以看到最新的 tweets:

moblin 2.1 主界面

moblin 2.1 主界面

还有这个,用户状态的页面,可以看到自己最新的一条 tweet

moblin 2.1 的用户状态标签

moblin 2.1 的用户状态标签

这个IM的页面也比较有趣,满眼的好友,呵呵

moblin 2.1 的朋友标签

moblin 2.1 的朋友标签

再补一个上网,还是google wave的图片

从moblin 2.1浏览网页: Google Wave

从moblin 2.1浏览网页: Google Wave

moblin 确实还是挺好玩的,在此还感谢陈绪又借给我一个MID玩,不过还玩得不太好,呵呵,先贴上来这篇 netbook 上的 moblin 吧  :)

Switch to our mobile site