实战:NetBSD4.0下使用RaidFrame制作Raid1硬盘镜像
August 19th, 2008 by skysbird
最近整理了一下在NetBSD下建立Raid1的过程,当时建立bsdchina.org服务器的时候由于时间仓促没有将整个的制作过程记录下来,前两天抽时间在虚机中重新做了这个过程,跟大家分享。
起因:现在一些SATA的主板上自带的Raid控制器并不能被NetBSD识别,因此如何将双硬盘制作为Raid1从而提高数据安全性成为一个比较头疼的问题,最终在bsdchina.org服务器上,采用了软件模拟Raid控制器的方式来实现Raid1。使用的软件是NetBSD标准安装中自带的RaidFrame软件。
过程:
1 在VMware中建立虚拟机,两块硬盘大小10G。
2 安装NetBSD4.0系统至disk0。
3 启动系统后,dmesg|grep -i raid 检查内核是否支持RaidFrame,如果输出类似下面的格式则表示内核有RaidFrame支持。
# dmesg|grep -i raid
Kernelized RAIDframe activated
4 如果没有RaidFrame支持,请先编译内核使其支持RaidFrame。
5 执行df,查看硬盘使用情况。

disklabel -r wd0

# fdisk /dev/rwd0d

通过上面的一些命令,可以帮助我了解目前虚机中第一块硬盘的情况,接下来要在第二块硬盘上做一些准备工作,核心的操作就是将第二块硬盘wd1中的全部扇区用0填充,命令如下:
# dd if=/dev/zero of=/dev/rwd1d bs=8k count=1
执行完毕后,通过如下的命令来确认第二块硬盘上的mbr和全部的数据已经被清空。
# disklabel -r wd1

观察上面的信息,offset都为0证明全部分区没有数据占用。由此可以确定硬盘上既没有数据也没有mbr引导记录。
接下来,我将第一块硬盘上的mbr中的引导记录传送至第二块硬盘。在此之前,先将第二块硬盘wd1设置为可启动。
# fdisk -0ua /dev/rwd1d
按照如下的内容进行回答。
fdisk: primary partition table invalid, no magic in sector 0
Disk: /dev/rwd1d
NetBSD disklabel disk geometry:
cylinders: 19386, heads: 16, sectors/track: 63 (1008 sectors/cylinder)
total sectors: 19541088BIOS disk geometry:
cylinders: 1023, heads: 255, sectors/track: 63 (16065 sectors/cylinder)
total sectors: 19541088Do you want to change our idea of what BIOS thinks? [n]Partition 0:The data for partition 0 is:sysid: [0..255 default: 169]
start: [0..1216cyl default: 63, 0cyl, 0MB]
size: [0..1216cyl default: 19541025, 1216cyl, 9542MB]
bootmenu: []
Do you want to change the active partition? [n] y
Choosing 4 will make no partition active.
active partition: [0..4 default: 0] 0
Are you happy with this choice? [n] y
We haven’t written the MBR back to disk yet. This is your last chance.
Partition table:
0: NetBSD (sysid 169)
start 63, size 19541025 (9542 MB, Cyls 0-1216/96/1), Active
1:
2:
3:
Bootselector disabled.
Should we write new partition table? [n] y
接下来查看第二块硬盘的数据情况:
# disklabel -r -e -I wd1
输出类似如下所示:
type: unknown
disk: Disk1
label:
flags:
bytes/sector: 512
sectors/track: 63
tracks/cylinder: 16
sectors/cylinder: 1008
cylinders: 19386
total sectors: 19541088
[...snip...]
16 partitions:
# size offset fstype [fsize bsize cpg/sgs]
a: 19541025 63 RAID # (Cyl. 0*-19385)
c: 19541025 63 unused 0 0 # (Cyl. 0*-19385)
d: 19541088 0 unused 0 0 # (Cyl. 0 -19385)
可以看到在a:区的offset为63,那么a区前面的部分便是mbr的引导记录,这表示引导记录已经传送至wd1。
接下来建立Raidframe设备的配置文件:
# vi /var/tmp/raid0.conf
START array
1 2 0START disks
/dev/wd9a
/dev/wd1aSTART layout
128 1 1 1START queue
fifo 100我们看到配置文件中写了wd9这个设备,这个设备对于系统来说是一个虚拟设备(psudeo设备),我们最后会用wd0替换掉它。
尽管如此,还是必须在系统中建立这个设备节点。
# cd /dev
# sh MAKEDEV wd9
# cd -
下一步,将使用这个配置文件来建立raid设备,命令如下:
# raidctl -v -C /var/tmp/raid0.conf raid0
输出如下:

正如预料那样,在wd9这个设备上出现错误,当它不存在就好了。初始化硬盘数据同步:
# raidctl -v -i raid0
Initiating re-write of parity
# tail -1 /var/log/messages
raid0: Error re-writing parity!
查看同步结果:
# raidctl -v -s raid0
输出:

接下来要用wd0来替换掉wd9这个设备,这个环节稍微有些复杂,需要进行一定的计算操作,为了简单起见,我的硬盘分区中除了swap分区便是一个大分区,一共只有2个分区。
执行如下命令来查看刚刚建立的raid设备情况:
# disklabel -r -e -I raid0
输出类似如下信息:
type: RAID
disk: raid
label: fictitious
flags:
bytes/sector: 512
sectors/track: 128
tracks/cylinder: 8
sectors/cylinder: 1024
cylinders: 19082
total sectors: 19540864
rpm: 3600
interleave: 1
trackskew: 0
cylinderskew: 0
headswitch: 0 # microseconds
track-to-track seek: 0 # microseconds
drivedata: 0# size offset fstype [fsize bsize cpg/sgs]
a: 19015680 0 4.2BSD 0 0 0 # (Cyl. 0 - 18569)
b: 525184 19015680 swap # (Cyl. 18570 - 19082*)
d: 19540864 0 unused 0 0 # (Cyl. 0 - 19082*)可以看出swap大小为525兆。
接下来格式化分区为4.2BSD FFSv1 File System
# newfs -O 1 /dev/rraid0a
接下来检查硬盘
# fsck -fy /dev/rraid0a
下面,需要建立真实的swap分区,刚刚看到的swap分区大小实际上是raid0这个设备的。由于raid0b作为swap分区,但是这个分区是无法作为真正的swap分区使用,因为如果系统挂掉了,进程调度停止了,那么是无法将dump出来的信息存储到raid0b这个分区的,因此这里采取了一个hack的方法,需要我们自己计算大小从而对分区表进行修改,使得我们在真实的wd1这个设备上建立一个分区大小使之与raid0b这个分区所标示的分区大小重叠一致。这步必须小心。接下来再回顾一下刚刚的raid0分区情况以及wd1的分区情况。
# disklabel raid0 8 partitions:
# size offset fstype [fsize bsize cpg/sgs]
a: 19015680 0 4.2BSD 1024 8192 64
b: 525184 19015680 swap
d: 19540864 0 unused 0 0 0 # disklabel wd1 8 partitions:
# size offset fstype [fsize bsize cpg/sgs]
a: 19541025 63 RAID
c: 19541025 63 unused 0 0
d: 19541088 0 unused 0 0
在所有的RAID设备中都保留有64个block大小的预留区域来保存RAID的一些结构信息。因此我们使用dc来计算实际的swap分区的偏移大小。将那块区域空出来为raid0b分区所用。
# dc 63 # offset of wd1a 64 # RF_PROTECTED_SECTORS + 19015680 # offset of raid0b +p 19015807 # offset of swap within wd1 q
接下来编辑现有的wd1的分区表信息。
# disklabel wd1 > disklabel.wd1
# vi disklabel.wd1
8 partitions:
# size offset fstype [fsize bsize cpg/sgs]
a: 19541025 63 RAID
b: 525184 19015807 swap
c: 19541025 63 unused 0 0
d: 19541088 0 unused 0 0
offset为上面计算出来的真实偏移量大小。 然后便可以应用这个修改后的配置了。
# disklabel -R -r wd1 disklabel.wd1
现在raid0的配置已经完成,但是raid0这个设备上还没有系统,接下来将wd0上的系统迁移到raid0a这个分区上:
# mount /dev/raid0a /mnt
# df -h /mnt
Filesystem Size Used Avail Capacity Mounted on
/dev/raid0a 9.0G 2.0K 8.6G 0% /mnt
# cd /; pax -v -X -rw -pe / /mnt然后编辑fstab文件,使用# vi /mnt/etc/fstab/dev/raid0a / ffs rw 1 1
/dev/raid0b none swap sw 0 0
/dev/wd0b none swap dp 0 0
kernfs /kern kernfs rw
procfs /proc procfs rw
# vi /mnt/etc/rc.conf
swapoff=YES
这是为了防止重启后出现同步错误。在wd1硬盘上安装启动文件。
# /usr/sbin/installboot -o timeout=30 -v /dev/rwd1a /usr/mdec/bootxx_ffsv1通过下面的命令将raid0设置成可自动配置。
# raidctl -v -A root raid0
raid0: Autoconfigure: Yes
raid0: Root: Yes
# tail -2 /var/log/messages
raid0: New autoconfig value is: 1
raid0: New rootpartition value is: 1
# raidctl -v -s raid0
[...snip...]
Autoconfig: Yes
Root partition: Yes
Last configured as: raid0
[...snip...]
# shutdown -r now一定要用shutdown重启,而不要使用reboot。重启后通过下面的命令查看raid0设备情况。
egrep -i “raid|root” /var/run/dmesg.boot
#
raid0: RAID Level 1
raid0: Components: component0[**FAILED**] /dev/wd1a
raid0: Total Sectors: 19540864 (9541 MB)
boot device: raid0
root on raid0a dumps on raid0b
root file system type: ffs# df -h
Filesystem Size Used Avail Capacity Mounted on
/dev/raid0a 8.9G 196M 8.3G 2% /
kernfs 1.0K 1.0K 0B 100% /kern# swapctl -l
Device 1K-blocks Used Avail Capacity Priority
/dev/raid0b 262592 0 262592 0% 0
# raidctl -s raid0
Components:
component0: failed
/dev/wd1a: optimal
No spares.
component0 status is: failed. Skipping label.
Component label for /dev/wd1a:
Row: 0, Column: 1, Num Rows: 1, Num Columns: 2
Version: 2, Serial Number: 2004082401, Mod Counter: 65
Clean: No, Status: 0
sectPerSU: 128, SUsPerPU: 1, SUsPerRU: 1
Queue size: 100, blocksize: 512, numBlocks: 19540864
RAID Level: 1
Autoconfig: Yes
Root partition: Yes
Last configured as: raid0
Parity status: DIRTY
Reconstruction is 100% complete.
Parity Re-write is 100% complete.
Copyback is 100% complete.
可以看出wd9那个设备还是error状态,接下来我们就需要将wd0这个设备替换掉wd9这个根本不存在的设备。在这之前将所有的两个硬盘的分区表、disklabel等信息进行备份。
# disklabel -r wd1 > /tmp/disklabel.wd1
# disklabel -R -r wd0 /tmp/disklabel.wd1
# disklabel -r wd0 > /tmp/disklabel.wd0
# disklabel -r wd1 > /tmp/disklabel.wd1
# diff /tmp/disklabel.wd0 /tmp/disklabel.wd1
# fdisk /dev/rwd0 > /tmp/fdisk.wd0
# fdisk /dev/rwd1 > /tmp/fdisk.wd1
# diff /tmp/fdisk.wd0 /tmp/fdisk.wd1
# mkdir /root/RFbackup
# cp -p /tmp/{disklabel,fdisk}* /root/RFbackup
将wd0a设备添加至raid0
# raidctl -v -a /dev/wd0a raid0
/netbsd: Warning: truncating spare disk /dev/wd0a to 241254528 blocks
# raidctl -v -s raid0
Components:
component0: failed
/dev/wd1a: optimal
Spares:
/dev/wd0a: spare
[...snip...]
# raidctl -F component0 raid0
RECON: initiating reconstruction on col 0 -> spare at col 2
11% |**** | ETA: 04:26 \
raidctl -S raid0
#
Reconstruction is 0% complete.
Parity Re-write is 100% complete.
Copyback is 100% complete.
Reconstruction status:
17% |****** | ETA: 03:08 -# raidctl -v -s raid0
Components:
component0: spared
/dev/wd1a: optimal
Spares:
/dev/wd0a: used_spare
[...snip...] # /usr/sbin/installboot -o timeout=15 -v /dev/rwd0a /usr/mdec/bootxx_ffsv1# shutdown -r now
完成。最后可以考虑测试一下我们的swap分区设置的是否正确,以免将来真的发生kernel panic的时候dump出来的文件造成我们的生产数据丢失。
具体方法如下:
在系统中按下Ctrl+Alt+Esc。进入内核调试模式输入命令 sync 或者 reboot 0×104 。这会强制将当前的内核映像存储到dump区域(wd0b)。如果一切都正常,那么我们的swap计算是正确的,如果失败了,那么好好检查一下,重新来过吧。:)