Archive for the ‘UNIX-like’ Category
Linux内核中的通用数据结构
Linux内核中实现了一些通用的数据结构,目前我所知的有:
- 双向链表:include/linux/list.h
- 红黑树:include/linux/rbtree.h lib/rbtree.c
- 基数树:include/linux/radix-tree.h lib/radix-tree.c
- 环形链表:include/linux/circ_buf.h
Linux内核中的通用数据结构,大部分提供的是“关节”连接点(这个是我自造的词)。这样的好处是程序员还是把主要精力放在目标数据结构上,使用通用函数完成基本操作,而不是把目标数据结构嵌入到通用数据结构中。
这两天在改Xen的代码,需要树去存储和查找数据,于是把Linux里面的红黑树移植到了Xen。顺便也把相关的代码写了。内核中的数据结构为了“通用”,通常只提供最小的功能集。链表还好,因为操作比较简单,所以list.h中全部把这些功能全部都实现了。红黑树比较复杂,插入和搜索这些操作要求使用者自己实现。
(原想把Xen改的那部分放出来,但是那样不大合适。这文章一点营养都没有,不用看了。)
Date: 2010-12-07 19:30:50 CST
HTML generated by org-mode 6.21b in emacs 23
Linux内核释放页表的过程
代码版本2.6.18-xen。
Linux在进程退出的时候,会调用mmput,mmput再调用exit_mmap。
先调用unmap_vmas去回收物理页框。unmap_vmas调用unmap_page_range。
unmap_page_range使用依次释放pud,pmd和pte。
相关函数是zap_pud_range,zap_pmd_range和zap_pte_range。
在zap_pte_range中,使用vm_normal_page把page结构取回,然后使用ptep_get_and_clear_full把PTE清0。最后把page的引用计数减1。
在unmap_vmas完成之后,再调用free_pgtables。它分别free_pgd_range,free_pud_range,free_pmd_range和free_pte_range。但是free_pte_range并不实际释放物理页,物理页在前面已经释放了。
Xen在zap_pte_range里面调用xen_l1_entry_update让Xen更新实际的PTE。非XenoLinux应该是直接更新PTE。
Sample Makefile for compiling LKM
obj-m := module.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
虚拟机网络及一些扯淡
今天又做了一个关于网络的实验,不过不是我发起和主导的。这个实验是把虚拟机里面的两块虚拟网卡做bonding(多块也是可以的,但是没有做),配置成failover模式。做failover的原因是,有时虚拟网卡会莫名其妙地死掉,网桥倒还是好的,希望做failover可以提高可用性。
原来还打算做load balance的,他们的意见是现在VM的throughput远远低于物理网卡的极限(什么原因?想想也知道),但是我的意见是,反正这都是软件模拟的,所以做出来意义也不大,而且很可能比原来还要慢。因为软件的逻辑更复杂,处理路径更长了,效果不会很好;物理机可行,那是因为大部分工作还是硬件完成的,性能上有保证。于是就先做failover的,看情况再做load balance。
做bonding的过程就不再说了,都是老一套。有个插曲就是刚刚开始测试的时候,他们没有把网卡设置为virtio,速度那个叫慢啊,VM与一台物理机通信只有3MB/s(千兆网络)。后来换成virtio了,速度稳定在20MB/s左右,虽然离千兆还差得远,但是也比原来的好很多。VirtIO的论文还没来得及看,有空得研究一下。
做failover出来的结果基本在我的预期中。两个网卡同时可用的时候,bond0默认选用eth0收发数据,速度约9MB/s,没错,就是9MB/s,比单卡的时候要慢很多。假如我把一个网卡down掉,failover生效,速度会上升到14MB/s。呵呵,有趣有趣。为了failover就得牺牲性能。做到这里,我想load balance也没有必要做了。
我以前也做过网络的测试,也写了post。怪异的地方是,实际使用的情况和测试出入比较大。不知道是系统越跑越慢,还是我需要严格区分测试和实用的区别。
我使用“virtual machine ethernet bonding”作为关键词google了一下别人的工作,发现除了Novell的社区上有一篇文章是真正讲在VM内做bonding之外,其他的文章都是写如何在物理机上做bonding然后让VM充分利用bonding提供的throughput能力。而且Novell的那个文章虽然写得不错,图文并茂的,但是却没有说明这样做的目的和好处,在我眼里没什么太大的价值。
那么把关注点放在物理机上做bonding然后让虚拟机用的文章上。情况不外乎两种。
一是直接把bond0这样的设备expose给VM,让VM直接用。这个找到一篇文章在Xen上面实现了,不是特别复杂。
二是把bond0连接到VMM的virtual switch / bridge上,通过内部分发算法去dispatch数据包。StackOverflow和一些blogger提到VMWare就是这样做的。但是因为VM不能意识到bonding的存在,以及vSwitch的分发算法设计问题,所以事实上单个VM不能享受到bonding带来的好处。但是host的出口提高,使得此host上运行多个VM时性能没有那么拿不出手(个人理解)。
本来写到这里就差不多了。但是这么扯淡的性能,用这个虚拟机有必要吗?我也经常问自己这样的问题。最后觉得还是需要具体问题具体分析了。服务整合(consolidation)是虚拟机的一个卖点,毕竟不是每个server都是under heavy stress的。3MB/s的速度够不够?某些情况下是足够了,不是吗?与其让CPU空转、硬件空费电,还不如充分利用一下呢。虚拟化本来的定位并不是万能药,不是银弹(silver bullet),而是在可管理性、可用性、节能、性能等多方面综合考虑的结果。虚拟化的应用,要看场合,结合实际。
目前我遇到唯一在生产环境中使用虚拟化技术的,只有ziqiang.net。我觉得这可以算做我的一个小案例分析一下。我的观点还是没变,自强目前的问题,虚拟化是无法解决的。自强的带宽不算大,大量电影下载已经占用很多出口资源,虚拟机的网络、磁盘I/O性能较低,有的时候会明显降低用户体验。虚拟机的强隔离性是很好,但是自强都是dedicated server,不存在合用的情况,是否有必要用到这么强的隔离性。架构的改动,我认为应该是在预见需求的情况下按需而动。按照目前的架构,可以用,再改也没什么必要。我想做OP的最好还是应该先收集数据,发现瓶颈,再做改动为好。不是说虚拟化技术不好,而是我们在使用技术之前,是否应该先把目的明确而不是跟着风潮走?技术是手段,而不是目的,这是我们应该常记心中的一句话。
(完)
Symbol Type Notation in System.map
System.map is created by `nm(1)’ with the following command:
$ nm /boot/vmlinux-xxxx > System.map-xxxx
Note that ‘vmlinux’ is not ‘vmlinuz’. We use vmlinuz to boot the system, while vmlinux is only an intermediate object when producing vmlinuz.
There are several types used in a kernel: AbBdDrRtTW .
So the symbol type notations are (taken from `man nm’) :
If lowercase, the symbol is local; if uppercase, the symbol is global (external).
- “A” The symbol’s value is absolute, and will not be changed by further linking.
- “B” “b” The symbol is in the uninitialized data section (known as BSS).
- “D” “d” The symbol is in the initialized data section.
- “R” “r” The symbol is in a read only data section.
- “T” “t” The symbol is in a text (code) section.
- “W” “w” The symbol is a weak symbol that has not been specifically tagged as a weak object symbol. When a weak defined symbol is linked with a normal defined symbol, the normal defined symbol is used with no error. When a weak undefined symbol is linked and the symbol is not defined, the value of the symbol is determined in a system-specific manner without error. On some systems, uppercase indicates that a default value has been specified.
There are other types of symbols, see manpage for details.
SSH自动加入远程主机密钥
SSH除了用于用户远程登录之外,也被很多软件用于安全通信、管理,比如Hadoop和OpenNebula都用它作为发送命令、交换数据的途径。
SSH默认的远程主机密钥策略是比较严格的。
- 不会自动把远程主机密钥加入到known_hosts中。
- 远程主机密钥发生改变时拒绝连接。
这样做,安全性是很高,用户使用也不会有太多的不方便。但是对于Hadoop和OpenNebula这样的系统却造成了麻烦。节点数量一多,手工确认主机密钥的代价很大,也不能进行自动配置。
其实SSH是可以改变这样的行为的。SSH客户端的配置文件中有一个选项StrictHostKeyChecking,默认是“ask”,可以把它改为“no”,这样主机密钥就会在连接时自动加入到known_hosts中去。此选项的具体含义,manpage的解释很清楚了。
注意,修改此选项的前提是,网络是可信和安全的,否则会有安全隐患。对于Hadoop和OpenNebula这样的环境是适用的。
Git忽略已跟踪文件的改动
我的Emacs配置文件已经放到github上面了,一方面记录更改,一方面也可以到处都可以下载来用。
目前我常用的机器上,都有一份dotemacs的clone。那么问题来了,假如对其中一个文件做了只适合本地的修改,那么commit就会把这些修改一起记录下来,然后push到github上面时,就会在各个系统之间的混乱。
因此我专门做了一个文件放在init-files里面,命名为99local-conf.el,最后才加载之。我想达到的效果是,在仓库里面做一个空文件来占位,但是每次提交时却不提交这个文件的修改。
gitignore只能忽略那些原来没有被track的文件,所以修改.gitignore是无效的。
正确的做法是在每个clone下来的仓库中手动设置不要检查特定文件的更改情况。
% git update-index --assume-unchanged /path/to/file
缺点就是每个新的仓库都必须手动设置一次。幸运的是,这样的设置每个仓库只要进行一次就够了。
Emacs按序加载配置文件
我希望Emacs可以有按序加载配置文件能力,简单的说,就是希望它能按照文件名的字母表排序来加载配置文件。这样我就可以在文件名前加上几个数字作为加载优先级了。这在Unix的世界里面是很常见的。
我是个懒人,总是希望有别人做好给我用。我换了好几个关键词去搜索,都没有找到别人写好的代码。也许是这个功能太简单不值得放到网上,也许是我的关键词不对,总之我就是没有搜到。
好吧,到了这一步也就不想再偷懒了,自己写点代码来实现这个功能吧。真的只是一点点。
(defun liuw-find-el-in-directory (directory)
"List the .el files in DIRECTORY."
;; This can be made recursive
(interactive "DDirectory: ")
(let (el-files-list
(current-directory-list
(directory-files-and-attributes directory t)))
(while current-directory-list
(if (equal ".el"
(substring (car (car current-directory-list)) -3))
(setq el-files-list
(cons (car (car current-directory-list)) el-files-list)))
(setq current-directory-list (cdr current-directory-list)))
el-files-list))
(defun liuw-get-sorted-el-list (directory)
(interactive "DDirectory: ")
(let ((l (sort (liuw-find-el-in-directory directory) 'string<)))
l))
(defun liuw-load-ordered-startup-el (directory)
(interactive "DDirectory: ")
(let ((l (liuw-get-sorted-el-list directory)))
(while l
(load-file (car l))
(setq l (cdr l)))))
Elisp早已生疏,所以写这点代码也颇费了点时间。只能感叹自己学艺不精了。
Org-mode的Code Blocks功能
在使用Emacs的Org-mode记笔记的时候,难免会遇到要输入代码的情况,使用code block功能来做,方便又美观。
一般的格式是:
#+begin_src language org-switches header-arguments CODE HERE #+end_src
比如说我要输入Ruby代码:
#+begin_src ruby puts 'hello world' #+end_src
还有更酷的。在code block中使用
C-c '
可以调用org-edit-src-code,直接切换到语言对应的mode进行输入,充分享受Emacs对语言的支持。
如果不在code block中调用org-edit-src-code,会进入Artist mode,可以用鼠标画图。
另外,code block还支持代码执行。
详见:http://orgmode.org/worg/org-contrib/babel/intro.php
Emacs中删除空行
m-x flush-lines
^$