<cloud>How VG active Even uninstall LVM

主要分析 如何学习lvm 是如何保证卸载可用,来开发自己的lvm 。

关于lvm 的逻辑卷配置信息 ,上次说过了,一般保存在磁盘的头部一个元数据, 同时可以通过 pvcfgbackup 和restore 来恢复。这里可以实现迁移和恢复。

这次来看看lvm 卸载的效果。  你可以自己先试试看 ,在你卸载 lvm (apt-get purge lvm2) 之后,reboot后你的逻辑卷组还在么。 如果你不放心可以之前先备份一下 :)

同时有一个好的方法看逻辑卷有没有正确挂上

> dmsetup info

 我们在安装的时候 一般显示如下:
apt-get install lvm2
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following NEW packages will be installed:
lvm2
0 upgraded, 1 newly installed, 0 to remove and 253 not upgraded.
Need to get 0 B/395 kB of archives.
After this operation, 1,184 kB of additional disk space will be used.
Selecting previously deselected package lvm2.
(Reading database ... 123988 files and directories currently installed.)
Unpacking lvm2 (from .../lvm2_2.02.66-4ubuntu2_i386.deb) ...
Processing triggers for man-db ...
Setting up lvm2 (2.02.66-4ubuntu2) ...
update-initramfs: deferring update (trigger activated)
Processing triggers for initramfs-tools ...
update-initramfs: Generating /boot/initrd.img-2.6.38-8-generic

看到最后一行了么 他会更新根文件系统。 而这个时候缺陷发生了, 他之后更新上一次更新的那个(说白了就是你系统安装好了之后的根文件系统) 而如果你之前重新编译了内核 使用了自己的根文件系统

grub.cfg 
menuentry '4debugszx, with Linux 2.6.38' --class ubuntu --class gnu-linux --class gnu --class os {
recordfail
insmod part_msdos
insmod ext2
set root='(hd0,msdos1)'
search --no-floppy --fs-uuid --set 7e439f6f-28eb-4a92-b543-dcf976056d3a
echo 'Loading Linux 2.6.38'
linux /boot/vmlinuz-2.6.38 root=UUID=7e439f6f-28eb-4a92-b543-dcf976056d3a ro single
echo 'Loading initial ramdisk ...'
initrd /boot/initrd.img-2.6.38
}

 

这样就会发生,你apt-get install lvm 的那个lvm 信息不会更新到你实际启动的根文件系统中。

1 ) 这个时候如果你重启 。会发生2种情况:

一个是逻辑卷一切ok :

 发生这种情况就是 你在 /etc/内  启动执行脚本中,添加了开机执行的程序。 这样他会去运行

sbin/ 下面的 vgchange 来激活逻辑卷:

一个是逻辑卷 lost :

发生这种情况 就是etc下面的开机启动脚本中没有lvm的激活信息。 这个比较倒霉。 当然你可以开机后自己

sbin/vgchange -a y  

一切ok

2) 如果你通过apt-get purge lvm2 卸载了lvm  你会发生他其实不更新 根文件系统initrdramfs

 
root@ubuntu:/home/szx/initrd# apt-get purge lvm2
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following package was automatically installed and is no longer required:
watershed
Use 'apt-get autoremove' to remove them.
The following packages will be REMOVED:
lvm2*
0 upgraded, 0 newly installed, 1 to remove and 253 not upgraded.
After this operation, 1,184 kB disk space will be freed.
Do you want to continue [Y/n]? y
(Reading database ... 124092 files and directories currently installed.)
Removing lvm2 ...
Purging configuration files for lvm2 ...
dpkg: warning: while removing lvm2, directory '/etc/lvm' not empty so not removed.
Processing triggers for man-db ...

你可能会觉得这是个失误 , 其实这是ubuntu 故意的一个设计,这样他保证了lvm 还存在于根文件系统(只要你没有通过 update-initramfs 更新。因为/usr/share/initramfs-tools/hooks/ 下面lvm的文件已经不存在了 )。

这样你就算你卸载了lvm 都能保证reboot 之后 逻辑卷还能正常激活。

我这里看了前后根文件系统的区别,关于lvm的主要是:

 
diff -r --brief initrdn initrdo
Only in initrdn/etc: lvm
Only in initrdn/lib/udev/rules.d: 56-lvm.rules
Only in initrdn/lib/udev/rules.d: 60-persistent-storage-lvm.rules
Only in initrdn/lib/udev/rules.d: 85-lvm2.rules
Only in initrdn/sbin: lvm
Only in initrdn/sbin: vgchange
Only in initrdn/scripts: init-premount

 

在根文件系统中关键的文件就是  

主要看一下 /lib/udev/rules.d: 85-lvm2.rules

 
zx@ubuntu:~/Downloads/initrdn/lib/udev/rules.d$ cat 85-lvm2.rules
# This file causes block devices with LVM signatures to be automatically
# added to their volume group.
# See udev(8) for syntax

SUBSYSTEM=="block", ACTION=="add|change", ENV{ID_FS_TYPE}=="lvm*|LVM*", \
RUN+="watershed sh -c '/sbin/lvm vgscan; /sbin/lvm vgchange -a y'"

 玄机就在这里,当然别的文件也不能少, 他们保证了启动根文件系统的时候就能激活分区。

下面深入了看一下

之前分析过 内核是通过 ioctl 为接口调用  dm_ctl_ioctl ->

调用最为关键的  populate_table 

实现 dm_table_add_target 

所以我通过虚拟串口调试内核停在了 dm_table_add_target 函数上。 发现

如果在根文件系统中 没有lvm信息的 使用/usr/sbin激活分区的时候。

 内核启动调试
* 2 Thread 645 (lvm) populate_table (param=<value optimized out>, param_size=3767832576)
---Type <return> to continue, or q <return> to quit---
at drivers/md/dm-ioctl.c:1157
1 Thread 1 (init) 0xc14a2f63 in context_switch () at kernel/sched.c:2946
(gdb) where
#0 populate_table (param=<value optimized out>, param_size=3767832576) at drivers/md/dm-ioctl.c:1157
#1 table_load (param=<value optimized out>, param_size=3767832576) at drivers/md/dm-ioctl.c:1205
#2 0xc139f578 in ctl_ioctl (file=<value optimized out>, command=<value optimized out>,
u=<value optimized out>) at drivers/md/dm-ioctl.c:1620
#3 dm_ctl_ioctl (file=<value optimized out>, command=<value optimized out>, u=<value optimized out>)
at drivers/md/dm-ioctl.c:1635
#4 0xc111df99 in vfs_ioctl (filp=0xcc2b2900, cmd=312, arg=0) at fs/ioctl.c:43
#5 0xc111eb71 in do_vfs_ioctl (filp=0xcdd3e240, fd=5, cmd=312, arg=152371368) at fs/ioctl.c:603
#6 0xc111ebf3 in sys_ioctl (fd=5, cmd=3241737481, arg=152371368) at fs/ioctl.c:623
#7 <signal handler called>

 Thread 645 (lvm) 是在 

120 Thread 668 (rc) ?? () at arch/x86/kernel/entry_32.S:300
119 Thread 667 (init) ?? () at arch/x86/kernel/entry_32.S:300
118 Thread 666 (kdmflush) 0xc14a2f63 in context_switch () at kernel/sched.c:2946
117 Thread 665 (udevd) 0xc14a2f63 in context_switch () at kernel/sched.c:2946
116 Thread 664 (sh) 0xc14a2f63 in context_switch () at kernel/sched.c:2946
115 Thread 663 (getty) 0xc14a2f63 in context_switch () at kernel/sched.c:2946
114 Thread 661 (rc) 0xc14a2f63 in context_switch () at kernel/sched.c:2946
113 Thread 599 (dhclient) 0xc14a2f63 in context_switch () at kernel/sched.c:2946
112 Thread 598 (wpa_supplicant) 0xc14a2f63 in context_switch () at kernel/sched.c:2946
111 Thread 576 (sh) 0xc14a2f63 in context_switch () at kernel/sched.c:2946
110 Thread 573 (sh) 0xc14a2f63 in context_switch () at kernel/sched.c:2946
109 Thread 566 (watershed) 0xc14a2f63 in context_switch () at kernel/sched.c:2946
108 Thread 464 (modem-manager) 0xc14a2f63 in context_switch () at kernel/sched.c:2946
107 Thread 600 (NetworkManager) 0xc14a2f63 in context_switch () at kernel/sched.c:2946

 

之间执行的一个线程,这个时候基本上已经到了启动的后期 sh 已经执行了

,如果根文件系统中有lvm 信息,并且可以执行那么 

 
* 2 Thread 213 (lvm) populate_table (param=<value optimized out>, param_size=3767705600)
at drivers/md/dm-ioctl.c:1157
1 Thread 1 (init) 0xc14a2f63 in context_switch () at kernel/sched.c:2946
(gdb)

 Thread 213 (lvm) 作为213个内核线程就执行了,这个时候内核启动才处于

 
104 Thread 215 (kdmflush) 0xc14a2f63 in context_switch () at kernel/sched.c:2946
103 Thread 214 (dmsetup) 0xc14a2f63 in context_switch () at kernel/sched.c:2946
102 Thread 212 (blkid) 0xc14a2f63 in context_switch () at kernel/sched.c:2946
101 Thread 211 (blkid) 0xc14a2f63 in context_switch () at kernel/sched.c:2946
100 Thread 205 (sh) 0xc14a2f63 in context_switch () at kernel/sched.c:2946
99 Thread 204 (watershed) 0xc14a2f63 in context_switch () at kernel/sched.c:2946
98 Thread 194 (scsi_eh_2) 0xc14a2f63 in context_switch () at kernel/sched.c:2946
97 Thread 193 (mpt/0) 0xc14a2f63 in context_switch () at kernel/sched.c:2946
96 Thread 192 (mpt_poll_0) 0xc14a2f63 in context_switch () at kernel/sched.c:2946
95 Thread 165 (udevd) 0xc14a2f63 in context_switch () at kernel/sched.c:2946

 

这个时候正在执行 根文件系统 中的执行程序。 

其实我也是通过调试内核才找到lvm 的启动机制。   而你只要几分钟就明白了  :)

这样开发自己的逻辑卷管理的时候,如果想实现lvm 的这种卸载还能激活的功能,就要把功夫放在打包自己的  initrdramfs 上了 。 

猜你喜欢

转载自sunzixun.iteye.com/blog/1018519