momo zone

调核人的blog

Monthly Archives: 五月 2011

mplayer compile error (svn 2011)

最近的mplayer 编译总是出错,准确的说svn2011 版本的基本都无法正常编译。就连1.0RC4 都不行。

In file included from h264.h:33:0,
                 from h264_cabac.c:33:
cabac.h: In function ‘get_cabac_noinline’:
cabac.h:527:5: error: can’t find a register in class ‘GENERAL_REGS’ while reloading ‘asm’
cabac.h:527:5: error: ‘asm’ operand has impossible constraints
问题发生在cabac.h:
 __asm__ volatile(
        “movl “RANGE    “(%2), %%esi            \n\t”
        “movl “LOW      “(%2), %%ebx            \n\t”
        BRANCHLESS_GET_CABAC(“%0”, “%2”, “(%1)”, “%%ebx”, “%%bx”, “%%esi”, “%%edx”, “%%dl”)
        “movl %%esi, “RANGE    “(%2)            \n\t”
        “movl %%ebx, “LOW      “(%2)            \n\t”
        :”=&a”(bit)
        :”r”(state), “r”(c)
        : “%”REG_c, “%ebx”, “%edx”, “%esi”, “memory”
goo 了一下发现这个问题很常见了,好像libavcode 较新版本都有这个问题。
解决方法是给CFLAG 加参数 -fomit-frame-pointer。 这样问题的确解决了,探究一下这个参数,顺便温习一下c函数的汇编过程。
GCC手册上面这么说:

Don’t keep the frame pointer in a register for functions that don’t need one. This avoids the instructions to save, set up and restore frame pointers; it also makes an extra register available in many functions. It also makes debugging impossible on some machines.

On some machines, such as the VAX, this flag has no effect, because the standard calling sequence automatically handles the frame pointer and nothing is saved by pretending it doesn’t exist. The machine-description macro “FRAME_POINTER_REQUIRED” controls whether a target machine supports this flag.

这里,引入了一个”frame pointer”的概念,什么是”stack frame pointer(SFP)”呢?

我们知道,backtrace是利用堆栈中的信息把函数调用关系层层遍历出来的,其中这里的堆栈信息就是SFP。
一般情况下,每一个函数都包含一个堆栈边界指针,也就是说会存在一个栈底和栈顶指针。在X86下,假设堆栈由上往下发展,栈底大地址而栈顶小地址,那么,通常情况下,寄存器ESP为栈顶指针,而EBP就为栈底指针。而EBP和ESP之间的空间就是这个函数的stack frame。
GCC在默认情况下会在每个函数的开始加入一些堆栈设置代码,而在函数退出的时候恢复原来的样子,SFP就是在这个时候设置的。还是看一下这个时候的汇编代码吧 😉

环境:X86+Redhat 9.0,gcc 3.2.2

源文件如下:

$ cat test.c
void a(unsigned long a, unsigned int b)
{
unsigned long i;
unsigned int j;

i = a;
j = b;

i++;

j += 2;

}

默认编译选项:
$ gcc -c test.c -o with_SFP.o

反汇编后是这个样子:
$ objdump -D with_SFP.o

with_SFP.o:     file format elf32-i386

Disassembly of section .text:

00000000 <a>:
0:   55                      push   %ebp
1:   89 e5                   mov    %esp,%ebp
3:   83 ec 08                sub    $0x8,%esp
6:   8b 45 08                mov    0x8(%ebp),%eax
9:   89 45 fc                mov    %eax,0xfffffffc(%ebp)
c:   8b 45 0c                mov    0xc(%ebp),%eax
f:   89 45 f8                mov    %eax,0xfffffff8(%ebp)
12:   8d 45 fc                lea    0xfffffffc(%ebp),%eax
15:   ff 00                   incl   (%eax)
17:   8d 45 f8                lea    0xfffffff8(%ebp),%eax
1a:   83 00 02                addl   $0x2,(%eax)
1d:   c9                      leave
1e:   c3                      ret
Disassembly of section .data:

可以看到函数ENTER时首先把上一层函数的EBP入栈,设置本函数的EBP,然后会根据临时变量的数量和对齐要求去设置ESP,也就产生了函数的stack frame。
我们再看看函数的返回:”leave”指令相当于”mov %ebp,%esp;pop %ebp”,也就是ENTER是两条指令的恢复过程,所以,后面的”ret”指令和”call”指令对应。
这里backtrace就可以根据现有函数EBP指针得知上一个函数的EBP—-栈底再往上保存着上一个函数的EBP和EIP,然后就可以得知函数调用的路径。

SFP是可以在编译时候优化掉的,用”-fomit-frame-pointer”选项

编译:
$ gcc -fomit-frame-pointer -c test.c -o no_SFP.o

$ objdump -D no_SFP.o

no_SFP.o:     file format elf32-i386

Disassembly of section .text:

00000000 <a>:
0:   83 ec 08                sub    $0x8,%esp
3:   8b 44 24 0c             mov    0xc(%esp,1),%eax
7:   89 44 24 04             mov    %eax,0x4(%esp,1)
b:   8b 44 24 10             mov    0x10(%esp,1),%eax
f:   89 04 24                mov    %eax,(%esp,1)
12:   8d 44 24 04             lea    0x4(%esp,1),%eax
16:   ff 00                   incl   (%eax)
18:   89 e0                   mov    %esp,%eax
1a:   83 00 02                addl   $0x2,(%eax)
1d:   83 c4 08                add    $0x8,%esp
20:   c3                      ret
Disassembly of section .data:

 这样代码执行长度缩短了,不使用ebp寄存器,应该能引起效率的提升。 但缺点也很明显,代码易读性变差,最重要的是不能用backtrace调试了。
这么说来是因为通用寄存器不够用,要借用ebp,所以必须加这个参数才能编译成功?
另外一个是提示找不到libdvdnav 和libdvdread(通过zypper 下载的so  没用)  ,这个是因为编译目录中没有这个两个。手动下载即可:
svn checkout svn://svn.mplayerhq.hu/dvdnav/trunk/libdvdread/src libdvdread4
svn checkout svn://svn.mplayerhq.hu/dvdnav/trunk/libdvdnav/src libdvdnav
傻瓜一点的直接把他写入configure:

diff --git a/configure b/configure
index ac64334..717f2e1 100755
--- a/configure
+++ b/configure
@@ -58,6 +58,26 @@
     touch ffmpeg/mp_auto_pull
   fi
+  if ! test -d libdvdread4 ; then
+    echo "No libdvdread4 directory, press enter to download with svn or CTRL+C to abort"
+    read tmp
+    if ! svn checkout svn://svn.mplayerhq.hu/dvdnav/trunk/libdvdread/src libdvdread4 ; then
+      rm -rf libdvdread4
+      echo "Failed to svn checkout libdvdread4"
+      exit 1
+    fi
+  fi
+
+  if ! test -d libdvdnav ; then
+    echo "No libdvdnav directory, press enter to download with svn or CTRL+C to abort"
+    read tmp
+    if ! svn checkout svn://svn.mplayerhq.hu/dvdnav/trunk/libdvdnav/src libdvdnav ; then
+      rm -rf libdvdnav
+      echo "Failed to svn checkout libdvdnav"
+      exit 1
+    fi
+  fi
+
 # Prevent locale nonsense from breaking basic text processing utilities
Advertisements

initrd 启动流程解析

1. init : 其实内核会优先查找initrd 根目录下的init ,如果没有再依次尝试sbin/init,/etc/init,/bin/init,/bin/sh/。这段代码在内核源码树 init/main.c 中:

static int __init kernel_init(void * unused)
{
	......

	if (!ramdisk_execute_command)
		ramdisk_execute_command = "/init";

	if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {
		ramdisk_execute_command = NULL;
		prepare_namespace();
	}

	/*
	 * Ok, we have completed the initial bootup, and
	 * we're essentially up and running. Get rid of the
	 * initmem segments and start the user-mode stuff..
	 */

	init_post();
        return 0;
}
static noinline int init_post(void)
{
       ......
        if (ramdisk_execute_command) {
                run_init_process(ramdisk_execute_command);
                printk(KERN_WARNING "Failed to execute %s\n",
                                ramdisk_execute_command);
        }

        /*
         * We try each of these until one succeeds.
         *
         * The Bourne shell can be used instead of init if we are
         * trying to recover a really broken machine.
         */
        if (execute_command) {
 run_init_process(execute_command);
 printk(KERN_WARNING "Failed to execute %s. Attempting "
 "defaults...\n", execute_command);
 }
 run_init_process("/sbin/init");
 run_init_process("/etc/init");
 run_init_process("/bin/init");
 run_init_process("/bin/sh");

        panic("No init found.  Try passing init= option to kernel. "
              "See Linux Documentation/init.txt for guidance.");
}

init 脚本首先判断slow_boot 变量是否为空,如果是则执行fast boot 。 所谓的fast boot即init 脚本不执行boot目录下各脚本所明示的依赖关系和执行条件,以及模块挂载请求 ,而是直接 执行无特别检查机制的run-all.sh 脚本,由它再 调用boot目录下的各脚本。过程中每个boot脚本开头的验证机制将不再起作用。下面 仅介绍fast boot的流程 。

2. run-all.sh : 很简单的脚本,依次调用boot目录下的初始化脚本

3.boot/*  : 一个个介绍篇幅会很大,所以这里挑选几个重要的讲大致流程 ,以及特别注意的地方。

01-devfunctions.sh: 里面全是函数,用来处理磁盘设备文件,major,minor 等等。 还有一个就是check_for_device() 他会在83-mount.sh 被调用。检查是否真正的 根目录所在的磁盘设备文件已经就绪。

02-start.sh: 完成shell环境变量初始化,部分虚拟目录的挂载比如/dev /proc /sys 等,创建基本的设备文件。格式化传过来的命令行参数。里面有一句比较特殊 exec < /dev/console > /dev/console 2>&1 他的作用是把/dev/console 的标准输出和标准错误输出 重新 定位给他自己 。意思就是所有输出都要显示在真实终端上。这里有个很有用的参数,linuxrc=trace 将启用追踪,再配合shell=1 ,和blogd 方便进行调试。

03-dm.sh: 很简单,就两行代码,直接贴出来明白 mkdir /dev/mapper mknod /dev/mapper/control c 10 63

03-rtc.sh: 好像这个无关紧要,等待实时时钟(即cmos时钟)在/sys/class/rtc/rtc0 出现。即使最后没出现也没有关系 ?

03-storage.sh:很重要: 用来设定真正的根目录在那个设备上 很简单: 就几行

. /config/mount.sh

if [ "$root" ]; then
    rootdev="$root"
fi

if [ "$nfsroot" ]; then
    rootdev=$nfsroot
fi

[ "$resume" ] && resumedev="$resume"

04-udev.sh:轮到udev出场了,其实也就两句 :

/sbin/udevd --daemon
/sbin/udevadm trigger

另外还有一个wait_for_events() 后面很多被call 到的情况。这个函数也就一句:

/sbin/udevadm settle --timeout=$udev_timeout

含义是udev 处理事件队列的时间 最长为udev_timeout 秒(阻塞)。

05-clock.sh:调整系统时钟? bin/warpclock 不知道何用

05-kms.sh: 设定是否启用kms

06-blogd.sh: 启用日志服务。日志文件记录在/var/log/boot.msg,同时链接到了/var/log/boot.msg。不过前者在upstart之后就看不到了。

11-block.sh: 设置块设备模块参数

21-dmraid.sh: 启用fake raid

22-kpartx.sh: 根据分区表生成对应分区的设备文件。不过这个脚本是空的,kpartx 交由udev的rule ,当有新磁盘被发现时会被自动调用。/etc/udev/rules.d/70-kpartx.rules:

# Create persistent links for dmraid tables
ENV{DM_UUID}=="DMRAID-*", \
        SYMLINK+="disk/by-id/$env{DM_TYPE}-$env{DM_NAME}"
ENV{DM_STATE}=="ACTIVE", ENV{DM_UUID}=="DMRAID-*", \
        RUN+="/sbin/kpartx -u -p _part /dev/$kernel"

81-resume.userspace.sh: 假如之前有s2disc那么这个脚本将调用用户空间程序来将把 resume device 中的镜像导入内存。

82-resume.kernelspace.sh: 好像没有什么实际作用,只是把81-resume.userspace.sh 中的resume device的major ,minor 放入/sys/power/resume 而已。

83-mount.sh: 非常重要的脚本,真正的根目录在这里被挂载。首先检查指定的根目录所在的设备是否真的在/dev下存在。然后利用udevadm info来获得文件系统类型。再后用fsck 检查文件系统。最后用mount 把它挂载到initrd 根目录下的root目录。文件系统的驱动模块什么时候加载的?

84-remount.sh: 依次在initrd  中的/root目录下检测并执行sbin/init , etc/init, bin/init ,bin/sh 。然后格式化/root/etc/fstab ,根据其中的参数重新挂载根目录到/root

91-createfb.sh: 创建帧缓冲

91-killblogd.sh  91-killudev.sh : 杀掉blogd和udevd

91-shell.sh : 如果内核参数有加 shell=1 那么run-all.sh 执行到这里就截止了,打开一个bash 取代后面流程的执行。

92-killblogd2.sh:杀掉blogd进程。

93-boot.sh: 移动并卸载一些虚拟目录比如dev,sys 等。 然后开始执行bin/run-init。

4.bin/run-init :在boot/93-boot.sh 中被执行(内核执行的第一个基于C库的程序):

exec /bin/run-init -c ./dev/console /root $init ${kernel_cmdline[@]}
echo could not exec run-init!
die 0

它的主要作用是remount 真正的根目录,并切换到真正根目录,打开/dev/console ,执行upstart程序,即真正根目录下的/sbin/init。也可以添加内核参数init=/bin/sh 来改变$init 变量。 这里一旦exec 执行成功,后续代码将不会再执行,因为/sbin/init 永不返回 。

5. /sbin/init : upstart 的起点。挂载真正的根目录后首先要执行的二进制程序,pid=1。

搞定 ICH8R ISW RAID

先搞清楚从硬件软件角度理解的raid 目前raid实现主要有3中类型:

软件RAID 软件RAID(简称sw raid)是由OS来提供的RAID功能,此举会耗用较多的CPU运算资源来作动。此种raid一般之被建立软raid的os所识别,所以它和硬raid在外在表现上有很大不同。 温馨提示:上的Linux软件RAID技术已是相当成熟,使用装置/ dev/md0的,/ dev/md1 ,/ dev/md2上依此类推,md是multiple device的意思。

硬件RAID 硬件RAID由专属的RAID运算芯片,位于raid卡或直接嵌入在主板上,这时候OS只需要驱动的RAID芯片即可,如此一来把RAID的任务分工给的RAID卡,CPU的也较为轻松,管理上会比较简便。由raid管理的磁盘在所有操作系统中均可以访问(前提是raid卡被驱动)。 温馨提示:硬件RAID厂商通常会提供监控RAID的状态工具,若是遇到磁碟有故障情形时,主机会闪烁故障灯号或是发出哔哔声。

ATARAID (BIOS RAID,FAKE RAID) 这类型的RAID介于软RAID与硬RAID之间,算是半个硬件RAID(但大部分时候仍称为sw raid),通常由主板南桥来“帮忙”的RAID运算,因此有假的RAID(FAKE RAID)的之称。 要启动这个RAID的功能,要先在BIOS的磁盘模式中更改为RAID,然后在开机POST后按ctrl+i 进入RAID设置界面(搞的和硬RAID很像)。再使OS能够正确辨识装置即可。因为这款RAID的要在BIOS的内开启,所以亦有人称之为BIOS中的RAID。 ####################################################################################################

拿到WDRE4 X2 自然想到的一件事就是组raid。raid5,raid10,raid01 都可以排除了,因为首先我手里没有多余的磁盘,其次我要的是性能。所以毫无疑问我选择了raid0。在bios里面设置raid0很简单,但需要注意的是stripe size设置。默认128KB,也就是说小于128KB的底层读写请求将不会分别放入两块磁盘。可以想到这个值大些对于大文件来说是件好事,而这个值小些对于小文件更有利。但如果设置过小将会导致读写稍大文件时候增加raid负担(对于fake raid而言也就是CPU负担了)。我取中庸的设置32K。 fake raid非常接近硬raid ,对于linux而言无需任何驱动和设置即可在安装界面看到分区表。但在安装完毕后 ls /dev/ 下不会有raid块设备。原因是内核取代了bios来管理磁盘,如果内核无法理解fake raid的标记及结构,那么内核根本就不知道fake raid的存在,而仅仅能看到单块的磁盘。 研究总结了一下linux下支持fake raid的 条件:

1.内核raid子系统编译:

device driver -> Multiple devices driver support(RAID and LVM) 。 其中的raid support 指的应该是软raid:

This is called “Software RAID” since the combining of
the partitions is done by the kernel. “Hardware RAID” means that the
combining is done by a dedicated controller; if you have such a
controller, you do not need to say Y here.
所以不用选中。
另外一个是Device mapper support :
Device-mapper is a low level volume manager. It works by allowing
people to specify mappings for ranges of logical sectors. Various
mapping types are available, in addition people may write their own
modules containing custom mappings if they wish.
Higher level volume managers such as LVM2 use this driver.
To compile this as a module, choose M here: the module will be
called dm-mod.

Device Mapper(DM)是Linux 2.6全面引入的块设备新构架,通过DM可以灵活地管理系统中所有的真实或虚拟的块设备。

DM以块设备的形式注册到Linux内核中,凡是挂载(或者说“映射”)于DM结构下的块设备,不管他们是如何组织,如何通讯,在Linux看来都是一个完整的DM块设备。因此DM让不同组织形式的块设备或者块设备集群在Linux内核面前有一个完整统一的DM表示。

dm targets 也就是指device mapper 所能支持的映射种类 :

 linear – maps continuous range of another block device
 striped (~RAID0) – striping across devices
 mirror (~RAID1) – mirroring devices
 crypt – encrypt data using CryptoAPI
 snapshot – online snapshots of block device
 multipath – access to multipath devices (misc. hw handlers)
 zero,error,delay – test and special targets
 truecrypt
...
 raid45 (~RAID4,5) – raid (with dedicated) parity
 loop – stack device over another or over file
 throttle, rwsplit, flakey – test targets

由此可见,DM是不了解磁盘文件机制的(比如LVM,分区表,文件系统,挂载机制)。他只能进行磁盘的底层IO ,比如访问某个扇区,某个柱面。而且每个IO都是经过重新映射过的。

dm-mod这个模块一定要有,或者直接编译到内核。成功启用后可以看到这个设备文件 :/dev/mapper/control

2.device-mapper 用户空间程序

配合dm-mod 内核模块来做磁盘映射管理。

具体提供:

/sbin/dmeventd , /sbin/dmsetup

用户接口

/lib/libdevmapper-event.so.1.02 /lib/libdevmapper.so.1.02

库文件

/lib/udev/rules.d/10-dm.rules

/lib/udev/rules.d/13-dm-disk.rules

/lib/udev/rules.d/95-dm-notify.rules

udev规则

/etc/init.d/boot.device-mapper

init 初始化脚本

/lib/mkinitrd/scripts/boot-dm.sh /lib/mkinitrd/scripts/setup-dm.sh

initrd rom盘脚本 这个很重要稍后会说明

这里举个例子,比如需要从现有物理磁盘映射出来一个虚拟磁盘,并将第9个扇区设置为坏块。最后用dd去访问,来模拟磁盘故障。

(1)

dmsetup create bad_disk
0 8 linear /dev/sdb1 0
8 1 error
9 204791 linear /dev/sdb1 9
蓝色部分的即为map table ,结束map table的输入可以按 ctrl+D 。
(2)

blockdev –setra 0 /dev/mapper/bad_disk # 设置预读扇区数为0

blockdev –getsz /dev/mapper/bad_disk # 获得磁盘扇区总数

(3)

linux:~ # dd if=/dev/mapper/bad_disk of=/dev/null bs=1k count=4
4+0 records in
4+0 records out
4096 bytes (4.1 kB) copied, 0.309579 s, 13.2 kB/s
linux:~ # dd if=/dev/mapper/bad_disk of=/dev/null bs=1k count=5
dd: reading `/dev/mapper/bad_disk’: Input/output error
4+0 records in
4+0 records out
4096 bytes (4.1 kB) copied, 0.00184017 s, 2.2 MB/s
count=4 时访问0-7扇区没有问题,当访问8 扇区是由于映射的扇区是error ,所以无法访问。

3.dmraid

基于DM的一个fake raid专用设置工具。它实际的作用是一个用户空间的驱动程序。它读取isw的metadata然后依据metadata 调用libdevmapper 建立 map table,实际对磁盘的操作也是由libdevmapper 和 dm-mod 完成的。

具体提供:

/sbin/dmevent_tool /sbin/dmraid

用户接口程序

/lib/libdmraid-events-isw.so /lib/libdmraid.so.1.0.0.rc16-3

库文件

/etc/init.d/boot.dmraid

init初始化脚本

/lib/mkinitrd/scripts/boot-dmraid.sh /lib/mkinitrd/scripts/setup-dmraid.sh

initrd rom 盘脚本

dmraid 的基本用法:

(1) #dmraid -l

asr     : Adaptec HostRAID ASR (0,1,10)
ddf1    : SNIA DDF1 (0,1,4,5,linear)
hpt37x  : Highpoint HPT37X (S,0,1,10,01)
hpt45x  : Highpoint HPT45X (S,0,1,10)
isw     : Intel Software RAID (0,1,5,01)
jmicron : JMicron ATARAID (S,0,1)
lsi     : LSI Logic MegaRAID (0,1,10)
nvidia  : NVidia RAID (S,0,1,10,5)
pdc     : Promise FastTrack (S,0,1,10)
sil     : Silicon Image(tm) Medley(tm) (0,1,10)
via     : VIA Software RAID (S,0,1,10)
dos     : DOS partitions on SW RAIDs
显示支持的fake raid的种类,也就是列出可以识别的metadata类型。
(2) #dmraid -a[y/n]
激活已建立的fake raid
(3) #dmraid -s
*** Group superset isw_cffghdacdg
–> Active Subset
name   : isw_cffghdacdg_WDRE4-400
size   : 1743812480
stride : 64
type   : stripe
status : ok
subsets: 0
devs   : 2
spares : 0
–> Active Subset
name   : isw_cffghdacdg_WDRE4-500
size   : 209715072
stride : 64
type   : stripe
status : ok
subsets: 0
devs   : 2
spares : 0
显示已存在的raid 组及属性。
(4)#dmraid -r
/dev/sdd: isw, “isw_cffghdacdg”, GROUP, ok, 976773165 sectors, data@ 0
/dev/sdc: isw, “isw_cffghdacdg”, GROUP, ok, 976773165 sectors, data@ 0
显示每个raid组 成员的属性

4.kpartx

根据块设备的分区表映射出分区对应的块设备。

比如/dev/sda 中的分区分别映射出/dev/sda1, /dev/sda2 等等。

#################################################################

前面都已经铺垫完了,下面切入正题

简单地说在各发行版中,想使用fake raid 很简单只要dmraid -ay 即可,然后mount /dev/mapper/isw_XXXX /mnt。 但如果想从一个fake raid 挂载根目录来启动 似乎大家的支持程度不一 。比如opensuse就不行。简单修改一下grub :

title Desktop -- openSUSE 11.1 - 2.6.38.4-1-desktop
    root (hd3,0)
    kernel /vmlinuz-2.6.38.4-1-desktop root=/dev/mapper/isw-ddhhicaebf_WDRE4-500_part2 resume=/dev/mapper/isw-ddhhicaebf_WDRE4-500_part3 showopts vga=0x31b
    initrd /initrd-2.6.38.4-1-desktop

启动时会提示:

Waiting for device /dev/mapper/isw_cffghdacdg_WDRE4-500_part2 to appear     然后等待超时后会hold

我看了一些说法好像是opensuse 支持mdadm而不支持redhat主导的dmraid 所以无法挂载。我认同这种说法,但我想肯定有办法自行解决这个问题。

加入kernel 参数 shell=1 可以在initrd 的 /bin/linuxrc 执行完之后开启一个shell 。

l /dev/mapper 发现是空目录,说明initrd /boot里面所有脚本执行完毕后也没有对raid 进行映射,无映射的设备文件。那么问题应该是initrd 没有包含dm-mod ,dmsetup 和 dmraid?

使用mkinitrd 中的 lsinitrd 可以列出目录,发现确实没有。看来要重新制作initrd 。通过man mkinitrd 得知-f 选项可以添加额外特性。其实mkinitrd是个脚本,他会根据当前系统环境生成合适的initrd, 不过我感觉这里存在bug, 他没有将系统中的raid放在眼里,所以生成的initrd 缺少模块支持。 根据前面的铺垫,要把dm,dmraid,kpartx 都加上:
mkinitrd -f  “dm dmraid kpartx” -k vmlinuz-2.6.37-desktop -i initrd-2.6.37-desktop -b /boot    
(-k 后面的一系列参数可以通过<initrd_root>/mkinitrd.conf 查看

展开 initrd的方法 :

mkdir /boot/initrd_dir

cd /boot/initrd_dir

cp ../initrd .

cpio -i -d < initrd

手动打包initrd的方法

find . | cpio -H newc -o > ../initrd.cpio

cd ..

cat initramfs.cpio | gzip > initrd.gz ) 

这样重新启动后然后会提示 Waiting for device /dev/mapper/isw_cffghdacdg_WDRE4-500_part2 to appear
看来要分析一下initrd 中/boot 目录下的脚本了
依照执行顺序找到 /boot/initrd_dir_3/boot/21-dmraid.sh
#!/bin/bash
#%stage: block
#%depends: dm
#%provides: dmroot
#%programs: /sbin/dmraid
#%if: -n “$root_dmraid”
#
##### Device Mapper Raid
##
## If the root device uses a software raid based on device mapper,
## this initializes and waits for the device to appear.
##
## Command line parameters
## ———————–
##
## root_dmraid=1        use device mapper raid
##
/sbin/dmraid -a y -p
wait_for_events

发现好像应该设置root_dmraid=1 内核启动参数才能执行 /sbin/dmraid -a y -p  ,最终修改grub 如下。

title Desktop -- openSUSE 11.1 - 2.6.38.4-1-desktop
    root (hd3,0)
    kernel /vmlinuz-2.6.38.4-1-desktop root=/dev/mapper/isw-ddhhicaebf_WDRE4-500_part2 resume=/dev/mapper/isw-ddhhicaebf_WDRE4-500_part3 root_dm=1 root_dmraid=1 showopts vga=0x31b
    initrd /initrd-2.6.38.4-1-desktop
最后终于搞定了 。这里还有一个小问题,boot log 会看到:
RAID set "isw_cffghdacdg_WDRE4-400" was activated
RAID set "isw_cffghdacdg_WDRE4-500" was activated
The dynamic shared library "libdmraid-events-isw.so" could not be loaded:
    libdmraid-events-isw.so: cannot open shared object file: No such file or directory
The dynamic shared library "libdmraid-events-isw.so" could not be loaded:
    libdmraid-events-isw.so: cannot open shared object file: No such file or directory
Trying manual resume from /dev/mapper/isw_cffghdacdg_WDRE4-500_part3
Invoking userspace resume from /dev/mapper/isw_cffghdacdg_WDRE4-500_part3
resume: libgcrypt version: 1.4.4
Trying manual resume from /dev/mapper/isw_cffghdacdg_WDRE4-500_part3
Invoking in-kernel resume from /dev/mapper/isw_cffghdacdg_WDRE4-500_part3
Waiting for device /dev/mapper/isw_cffghdacdg_WDRE4-500_part2 to appear:  ok
RAID set “isw_cffghdacdg_WDRE4-400” was activated
RAID set “isw_cffghdacdg_WDRE4-500” was activated
ERROR:  Unable to register a device mapper event handler for device “isw_cffghdacdg_WDRE4-400”
ERROR:  Unable to register a device mapper event handler for device “isw_cffghdacdg_WDRE4-500”
Trying manual resume from /dev/mapper/isw_cffghdacdg_WDRE4-500_part3
Invoking userspace resume from /dev/mapper/isw_cffghdacdg_WDRE4-500_part3
resume: libgcrypt version: 1.4.4
Trying manual resume from /dev/mapper/isw_cffghdacdg_WDRE4-500_part3
Invoking in-kernel resume from /dev/mapper/isw_cffghdacdg_WDRE4-500_part3
Waiting for device /dev/mapper/isw_cffghdacdg_WDRE4-500_part2 to appear:  ok
不过未发现什么影响。
晒win2008R2-SP1 下 HDT 成绩:

 

2015/1/2 update:

发现dmraid已经渐渐合并到mdadm了 <http://www.phoronix.com/scan.php?page=news_item&px=MTUxOTk&gt; :

Besides wanting to enable SSD TRIM support for Ubuntu Linux, developers are also looking at moving from DMRAID to MDADM for fake/software RAID configurations on the desktop operating system.

MDADM has now the ability to manage external meta-data RAID devices and for some devices such as Intel Matrix RAID it’s now preferred over using the common DMRAID package. With the broader move towards MDADM for Linux RAID administrator, Ubuntu developers are looking to follow this movement and transition to MDADM by default.

MDADM supports all the standard RAID configurations (RAID 0/1/4/5/6/10) and works with both partitions and entire disks. MDADM also supports container, multi-path, faulty, and linear disk configurations as well.

For those exploring RAID on Linux or want to catch up on MDADM, see the developer blog or the Git repository. What’s new today is that Ubuntu developers are hoping to switch to MDADM by default over DMRAID.

There’s changes needed by the Ubuntu installer, initramfs changes, dmraid/imsm migration items to work through, and other issues to work through, but it’s now on the agenda for Ubuntu and potentially to be changed in 14.04 LTS. More details on the MDADM Ubuntu plans can be found via this Ubuntu vUDS page.

新的发行版默认使用mdadm管理fake raid,但貌似还有点问题,不支持一个磁盘组中的多个卷。解决办法是停掉mdadm -S /dev/md0。然后再dmraid -ay。

WD RE4 企业级硬盘

盘点 一下手里的硬盘,希捷,迈拓,IBM,日立都有了,好像还差了一个WD,不过WD现在是鹤立鸡群,拥有最大的市场份额,最好用户口碑(桌面平台)。其中企业级的产品线里RE是定位企业级产品。 最近搞了两块RE4 500G,测了一下,结果囧了 :
不错的曲线,不错平均速度还没有日立快。


这张图亮了,支持模式UDMA 6 当前模式UDMA 7 !!??  后证实是主板bug,换个sata接口就ok


这一块成绩神了,平坦曲线?意思是这块盘更好?还是有问题? 问了taobao某卖家,说我RP 好,搞到一块神盘~

再问taobao卖家之前还换了一块,结果还是非平坦曲线。看来RP 好不过一次。

wifi region setup

深晦wifi设置之道的人都知道channel 的最佳设置,之前我有谈过这个问题,就是1,6,11这个几个channel是独立的,受到的干扰比较少。其实呢 还有12 (Europe and Japan), 13 (Europe and Japan), and 14 (Japan only)频道,实际使用的情况是13频道的效果更好(14频道没有用过)

不过也不是所有的卡都有这么宽的频道,不幸买到US限定的就只有1-11频道。可恶,我手里就有这样一块烂卡。

搞定这个问题有两个途径:

1. 对cfg80211 内核模块设定参数:

ieee80211_regdom=JP

2. 使用用户空间的CRDA 工具:

export COUNTRY=JP;crda

已尝试,确认不能用,返回:Failed to set regulatory domain: -22 ,也许是调用crda的时机不对。

*****************************************************

不过我试过好像加内核模块参数对intel 4965/5X00 不起作用,而对realtek 8187是管用的:

比如我的8187 默认的region就有14个频道:

# iw reg get
country 00:
        (2402 - 2472 @ 40), (3, 20)
        (2457 - 2482 @ 20), (3, 20), PASSIVE-SCAN, NO-IBSS
        (2474 - 2494 @ 20), (3, 20), NO-OFDM, PASSIVE-SCAN, NO-IBSS
        (5170 - 5250 @ 40), (3, 20), PASSIVE-SCAN, NO-IBSS
        (5735 - 5835 @ 40), (3, 20), PASSIVE-SCAN, NO-IBSS
# iwlist wlan0 f
wlan0     14 channels in total; available frequencies :
          Channel 01 : 2.412 GHz
          Channel 02 : 2.417 GHz
          Channel 03 : 2.422 GHz
          Channel 04 : 2.427 GHz
          Channel 05 : 2.432 GHz
          Channel 06 : 2.437 GHz
          Channel 07 : 2.442 GHz
          Channel 08 : 2.447 GHz
          Channel 09 : 2.452 GHz
          Channel 10 : 2.457 GHz
          Channel 11 : 2.462 GHz
          Channel 12 : 2.467 GHz Channel 13 : 2.472 GHz Channel 14 : 2.484 GHz

假设这里要限定成US,即 1-11 channel ,可以这样做:

# modprobe -r iwlagn iwlcore rtl8187 mac80211 cfg80211
# modprobe -v cfg80211 ieee80211_regdom=US
insmod /lib/modules/2.6.38.4-1-desktop/kernel/net/rfkill/rfkill.ko
insmod /lib/modules/2.6.38.4-1-desktop/kernel/net/wireless/cfg80211.ko ieee80211_regdom=US
# iw reg get
country US:
        (2402 - 2472 @ 40), (3, 27)
        (5170 - 5250 @ 40), (3, 17)
        (5250 - 5330 @ 40), (3, 20), DFS
        (5490 - 5600 @ 40), (3, 20), DFS
        (5650 - 5710 @ 40), (3, 20), DFS
        (5735 - 5835 @ 40), (3, 30)
# modprobe rtl8187
# iwlist wlan0 f
wlan0     11 channels in total; available frequencies :
          Channel 01 : 2.412 GHz
          Channel 02 : 2.417 GHz
          Channel 03 : 2.422 GHz
          Channel 04 : 2.427 GHz
          Channel 05 : 2.432 GHz
          Channel 06 : 2.437 GHz
          Channel 07 : 2.442 GHz
          Channel 08 : 2.447 GHz
          Channel 09 : 2.452 GHz
          Channel 10 : 2.457 GHz
          Channel 11 : 2.462 GHz

内核参数的确起作用了

而且通过sys也可以查看region:

cat /sys/module/cfg80211/parameters/ieee80211_regdom

kernel log的讯息:

[26950.201850] cfg80211: Calling CRDA for country: US
[26950.205166] cfg80211: Regulatory domain changed to country: US
[26950.205168] cfg80211:     (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)
[26950.205171] cfg80211:     (2402000 KHz - 2472000 KHz @ 40000 KHz), (300 mBi, 2700 mBm)
[26950.205173] cfg80211:     (5170000 KHz - 5250000 KHz @ 40000 KHz), (300 mBi, 1700 mBm)
[26950.205175] cfg80211:     (5250000 KHz - 5330000 KHz @ 40000 KHz), (300 mBi, 2000 mBm)
[26950.205177] cfg80211:     (5490000 KHz - 5600000 KHz @ 40000 KHz), (300 mBi, 2000 mBm)
[26950.205179] cfg80211:     (5650000 KHz - 5710000 KHz @ 40000 KHz), (300 mBi, 2000 mBm)
[26950.205181] cfg80211:     (5735000 KHz - 5835000 KHz @ 40000 KHz), (300 mBi, 3000 mBm)

可以看到挂载内核加参数实际也调用了CRDA ??没错,就在执行modprobe之后,cfg80211实际只是把参数传给crda,然后去设置。如果手动操作也ok:
iw reg set JP
上述工具命令在挂载网卡驱动模块后将失效哦

如果要在开机设置cfg80211的参数可以这样:

echo options cfg80211 ieee80211_regdom=US >>/etc/modprobe.d/XX-option

关于CRDA和rgdb 的信息可以查看这个链接http://wireless.kernel.org/en/developers/Regulatory/#The_regulatory_database