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 上了 。 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章