Linux系統診斷小技巧(15):啟停問題之如何修復檔案系統損壞
題外話
我們先講什麼是 檔案系統 和需要的工具。
ofollow,noindex" target="_blank">檔案系統
現在的儲存種類眾多、堆疊繁雜。但是使用者直接的介面還是 檔案系統 。對於Linux和開源社群而言,眾多的軟體也是依賴 檔案系統 。比如SQL/">MySQL和PostgreSQL資料庫就是直接呼叫檔案系統介面的,而不像Oracle資料庫,能夠越過檔案系統層。
Linux系統上檔案系統眾多。但是比較常用的是 Ext 和 XFS" rel="nofollow,noindex" target="_blank">Xfs 檔案系統。當前使用比較普遍的是Ext4檔案系統。
這裡我們以Ext4檔案系統為例。
三大利器
關於工具的重要性我們就不絮叨了。解決啟停問題,一定要有三大利器的輔助:快照、VNC和錄屏工具。
關於這些工具,請參考[
Linux系統診斷小技巧(13):啟停問題之如何修復grub損壞]( https://yq.aliyun.com/articles/642902) 。
bind掛載
修復啟停時經常需要做chroot操作,即我們要在一個新的根檔案系統內操作。但是,只執行chroot是不夠的。我們還需要掛載/dev、/proc和/sys目錄。這樣才能使用在 chroot 後繼續使用系統資料。
關於bind掛載,同樣請參考[
Linux系統診斷小技巧(13):啟停問題之如何修復grub損壞]( https://yq.aliyun.com/articles/642902) 有關章節。
回到話題
檔案系統 損壞,是導致系統啟動失敗比較常見的原因。檔案系統損壞,比較常見的原因是分割槽丟失和檔案系統需要手工修復。
現場復現
我們人為的破壞分割槽表資訊。
準備測試環境
我們先準備一個供測試的檔案系統。具體操作如下
# # 下面我們以第二塊磁碟為例,並且假設其磁碟路徑是/dev/vdb # # 1. 檢查新磁碟的情況 fdisk -l -u /dev/vdb # 2. 新建分割槽 fdisk /dev/vdb # 3. 建立檔案系統 mkfs.ext4 /dev/vdb1 # 4. 配置系統啟動掛載新建檔案系統 echo '/dev/vdb1 /opt ext4defaults 02' >> /etc/fstab # 5. 重啟系統以便驗證配置符合預期 reboot # 6. 驗證掛載成功 mount -l | egrep /dev/vdb1
先看準備檔案系統的具體操作

驗證掛載情況
可見掛載是成功的。
損壞測試:fstab配置錯誤
我們通過下面的方式測試下
# defaults -> default # 可以直接手工調整 # 可以用ed ed -s /etc/fstab <<EOF /\/dev\/vdb1/s/defaults/default/ w EOF # 當然也可以使用sed sed -i -e '/\/dev\/vdb1/s/defaults/default/' /etc/fstab
看下啟動失敗情況
損壞測試:分割槽表丟失
我們先把檔案系統的掛載恢復正常,再手工破壞分割槽表進行測試
# 1. 解除安裝檔案系統 umount /dev/vdb1 # 2. 檢查分割槽情況 fdisk -l -u /dev/vdb # 3. 直接使用fdisk來刪除分割槽 fdisk -u /dev/vdb # 4. 驗證刪除了分割槽 fdisk -l -u /dev/vdb
操作示例如下

看下啟動失敗情況(系統啟動過程止步不前,但是也沒有明顯的報錯資訊。所以錄屏工具是有必要的)
如何修復問題?
因為當前例項啟動失敗,這種情況下在當前例項上,我們沒有用shell來解決問題。所以,我們需要先解決在哪裡來修復的問題。
解決這個問題的方案比較多,運維人員常見的手段是使用LiveCD。這裡我們推薦使用快照的方式。
配置錯誤
這種情況只要把錯誤配置修改完畢即可解決問題,我們略過不談。
分割槽表丟失問題
修復方案的依據
分割槽表丟失,只要重新建立分割槽表即可。因為分割槽表資訊只涉及變更磁碟上第1個扇區指定位置的內容。所以,只要確認有分割槽情況,在分割槽表丟失的情況下,重做分割槽是不會損壞磁碟上的資料的。但是分割槽起始位置和尺寸需要正確,否則不能解決問題。
分割槽的大小,因為大家(基本)都是一個磁碟分一個區,所以(幾乎)不用考慮分割槽大小。起始位置確定後,大小選擇fdisk給出的就好。所以,問題的關鍵是如何確定分割槽的開始位置。
我們以常見的Ext檔案系統為例,具體請參看 如何從Ext3或者Ext4檔案系統推斷分割槽位置 。
重建分割槽
重建分割槽可以按照下面的步驟來實現。
確定分割槽起始位置
首先,我們需要先確認分割槽上的檔案系統資訊。這有多種方式:
- 檢視 /etc/fstab 和 /etc/mtab 配置檔案。
- 如果檔案系統還是掛載情形,則檢視 /proc/mounts
- 直接檢查檔案系統魔數。
- 從系統日誌追查。
我們看下直接檢查檔案系統魔數的例子,並用 fdisk 工具核實下
# # 1. ext*檔案系統的魔數是: 53 ef # [root@iz2ze122w6gewwurz1e637z ~]# dd if=/dev/vdb bs=512 count=4096 2>/dev/null | \ > od -tx1 | perl -ne ' >chomp; >if (/^([0-7]+)\s # 磁碟資料的位置 >([0-9a-f][0-9a-f]\s){8} # 越過無關資料 >53\sef\s # 模數 >0[124]\s00\s0[123]\s00\s # 檔案系統狀態和出錯後的行為配置 >/x) { >my $s=int((oct $1)/512)-2; >print qq[$s $_\n]; >}' 56 0072060 72 46 cd 5b 00 00 ff ff 53 ef 01 00 01 00 00 00 # # 2. 檢查到魔數,即是Ext*檔案系統。從魔數反推出的分割槽起始扇區是56扇區。 # [root@iz2ze122w6gewwurz1e637z ~]# fdisk -l -u /dev/vdb 磁碟 /dev/vdb:1099.5 GB, 1099511627776 位元組,2147483648 個扇區 Units = 扇區 of 1 * 512 = 512 bytes 扇區大小(邏輯/物理):512 位元組 / 512 位元組 I/O 大小(最小/最佳):512 位元組 / 512 位元組 磁碟標籤型別:dos 磁碟識別符號:0x00088bd9 裝置 BootStartEndBlocksIdSystem /dev/vdb1562147483647107374179683Linux [root@iz2ze122w6gewwurz1e637z ~]# # # 3. fdisk給出的起始扇區是56。這與我們從魔數推斷到的結果是一致的。 #
修復
示例:復現問題現場
我們如果通過fdisk工具來對 /dev/vdb 重新分割槽。如果在/etc/fstab中做了配置,那麼重啟會失敗。具體失敗報錯請參考上面的資訊。如果不重啟直接掛載,則會遇到下面的報錯
# # 1. 直接掛載 # [root@iz2ze122w6gewwurz1e637z ~]# mount /dev/vdb1 /opt mount: /dev/vdb1 is write-protected, mounting read-only mount: unknown filesystem type '(null)' # # 2. 掛載失敗了 # [root@iz2ze122w6gewwurz1e637z ~]# mount -l | egrep /dev/vdb # # 3.為什麼掛載失敗了呢?因為fdisk把分割槽起始位置設定為2048了 # [root@iz2ze122w6gewwurz1e637z ~]# fdisk -u -l /dev/vdb Disk /dev/vdb: 1099.5 GB, 1099511627776 bytes, 2147483648 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk label type: dos Disk identifier: 0x00088bd9 Device BootStartEndBlocksIdSystem /dev/vdb120482147483647107374080083Linux [root@iz2ze122w6gewwurz1e637z ~]#
重建分割槽
因為 fdisk 工具總是把起始扇區設定為2048,不能調整,所以我們使用parted工具。具體修復過程如下
[root@iz2ze122w6gewwurz1e637z ~]# parted /dev/vdb GNU Parted 3.1 Using /dev/vdb Welcome to GNU Parted! Type 'help' to view a list of commands. # # 1. 使用扇區作為預設單位 # (parted) unit s # # 2. 檢查當前的分割槽情況 # (parted) print Model: Virtio Block Device (virtblk) Disk /dev/vdb: 2147483648s Sector size (logical/physical): 512B/512B Partition Table: msdos Disk Flags: NumberStartEndSizeTypeFile systemFlags 12048s2147483647s2147481600sprimary # # 3. 刪除問題分割槽 # (parted) rm 1 # # 4. 重建分割槽 # (parted) mkpart Partition type?primary/extended? primary File system type?[ext2]? ext4 Start? 56# 起始扇區調整為56 End? 2147483647 # 扇區編號是從0開始的。因此最後一個扇區,是扇區總數減1 Warning: The resulting partition is not properly aligned for best performance. Ignore/Cancel? Ignore # 這是我們所要的分割槽情況,因此忽略報警 (parted) q Information: You may need to update /etc/fstab. # # 5. 分割槽重建成功 [root@iz2ze122w6gewwurz1e637z ~]# tune2fs -l /dev/vdb1 tune2fs 1.42.9 (28-Dec-2013) Filesystem volume name:<none> Last mounted on:<not available> Filesystem UUID:0d51624e-5f97-46bb-8423-63a6e5e72d1c Filesystem magic number:0xEF53 Filesystem revision #:1 (dynamic) Filesystem features:has_journal ext_attr resize_inode dir_index filetype needs_recovery extent 64bit flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize Filesystem flags:signed_directory_hash Default mount options:user_xattr acl Filesystem state:clean Errors behavior:Continue Filesystem OS type:Linux Inode count:67108864 Block count:268435449 Reserved block count:13421772 Free blocks:264170080 Free inodes:67108853 First block:0 Block size:4096 Fragment size:4096 Group descriptor size:64 Reserved GDT blocks:1024 Blocks per group:32768 Fragments per group:32768 Inodes per group:8192 Inode blocks per group:512 Flex block group size:16 Filesystem created:Mon Oct 22 11:39:29 2018 Last mount time:Mon Oct 22 12:12:30 2018 Last write time:Mon Oct 22 12:12:30 2018 Mount count:1 Maximum mount count:-1 Last checked:Mon Oct 22 11:39:29 2018 Check interval:0 (<none>) Lifetime writes:134 MB Reserved blocks uid:0 (user root) Reserved blocks gid:0 (group root) First inode:11 Inode size:256 Required extra isize:28 Desired extra isize:28 Journal inode:8 Default directory hash:half_md4 Directory Hash Seed:0f70f076-e2f1-4f0e-bc37-e950a58e0d0c Journal backup:inode blocks [root@iz2ze122w6gewwurz1e637z ~]# mount /dev/vdb1 /opt [root@iz2ze122w6gewwurz1e637z ~]# [root@iz2ze122w6gewwurz1e637z ~]# mount -l | egrep /dev/vdb1 /dev/vdb1 on /opt type ext4 (rw,relatime,data=ordered) [root@iz2ze122w6gewwurz1e637z ~]# # 終焉 祝探索愉快。