天天看點

Linux系統診斷小技巧(15):啟停問題之如何修複檔案系統損壞題外話回到話題如何修複問題?終焉

題外話

我們先講什麼是檔案系統和需要的工具。

檔案系統

現在的存儲種類衆多、堆棧繁雜。但是使用者直接的接口還是

。對于Linux和開源社群而言,衆多的軟體也是依賴

。比如MySQL和PostgreSQL資料庫就是直接調用檔案系統接口的,而不像Oracle資料庫,能夠越過檔案系統層。

Linux系統上檔案系統衆多。但是比較常用的是

Ext

Xfs

檔案系統。目前使用比較普遍的是Ext4檔案系統。

這裡我們以Ext4檔案系統為例。

三大利器

關于工具的重要性我們就不絮叨了。解決啟停問題,一定要有三大利器的輔助:快照、VNC和錄屏工具。

關于這些工具,請參考

Linux系統診斷小技巧(13):啟停問題之如何修複grub損壞

bind挂載

修複啟停時經常需要做chroot操作,即我們要在一個新的根檔案系統内操作。但是,隻執行chroot是不夠的。我們還需要挂載/dev、/proc和/sys目錄。這樣才能使用在chroot後繼續使用系統資料。

關于bind挂載,同樣請參考

有關章節。

回到話題

損壞,是導緻系統啟動失敗比較常見的原因。檔案系統損壞,比較常見的原因是分區丢失和檔案系統需要手工修複。

現場複現

我們人為的破壞分區表資訊。

準備測試環境

我們先準備一個供測試的檔案系統。具體操作如下

#
# 下面我們以第二塊磁盤為例,并且假設其磁盤路徑是/dev/vdb
#
# 1. 檢查新磁盤的情況
fdisk -l -u /dev/vdb
# 2. 建立分區
fdisk /dev/vdb
# 3. 建立檔案系統
mkfs.ext4 /dev/vdb1
# 4. 配置系統啟動挂載建立檔案系統
echo '/dev/vdb1 /opt ext4    defaults 0       2' >> /etc/fstab
# 5. 重新開機系統以便驗證配置符合預期
reboot
# 6. 驗證挂載成功
mount -l | egrep /dev/vdb1           

先看準備檔案系統的具體操作

[root@iz2ze122w6gewwurz1e637z ~]# fdisk -l -u /dev/vdb 1. 檢查新磁盤的情況

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 Boot      Start         End      Blocks   Id  System
[root@iz2ze122w6gewwurz1e637z ~]# fdisk /dev/vdb # 2. 建立分區
Welcome to fdisk (util-linux 2.23.2).

Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Command (m for help): n
Partition type:
   p   primary (0 primary, 0 extended, 4 free)
   e   extended
Select (default p): p
Partition number (1-4, default 1): 
First sector (2048-2147483647, default 2048): 
Using default value 2048
Last sector, +sectors or +size{K,M,G} (2048-2147483647, default 2147483647): 
Using default value 2147483647
Partition 1 of type Linux and of size 1024 GiB is set

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.
[root@iz2ze122w6gewwurz1e637z ~]# mkfs.ext4 /dev/vdb1 # 3. 建立檔案系統
mke2fs 1.42.9 (28-Dec-2013)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
67108864 inodes, 268435200 blocks
13421760 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=2415919104
8192 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks: 
    32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 
    4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968, 
    102400000, 214990848

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done     

[root@iz2ze122w6gewwurz1e637z ~]# echo '/dev/vdb1 /opt ext4    defaults 0       2' >> /etc/fstab # 4. 配置系統啟動挂載建立檔案系統           

現在重新開機系統,驗證挂載情況

Linux系統診斷小技巧(15):啟停問題之如何修複檔案系統損壞題外話回到話題如何修複問題?終焉

可見挂載是成功的。

損壞測試: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           
Linux系統診斷小技巧(15):啟停問題之如何修複檔案系統損壞題外話回到話題如何修複問題?終焉

看下啟動失敗情況(後續的記錄系統抱怨截圖時的按鍵無法識别)。系統啟動中斷了

Linux系統診斷小技巧(15):啟停問題之如何修複檔案系統損壞題外話回到話題如何修複問題?終焉

損壞測試:分區表丢失

我們先把檔案系統的挂載恢複正常,再手工破壞分區表進行測試

# 1. 解除安裝檔案系統
umount /dev/vdb1
# 2. 檢查分區情況
fdisk -l -u /dev/vdb
# 3. 直接使用fdisk來删除分區
fdisk -u /dev/vdb
# 4. 驗證删除了分區
fdisk -l -u /dev/vdb           

操作示例如下

Linux系統診斷小技巧(15):啟停問題之如何修複檔案系統損壞題外話回到話題如何修複問題?終焉

看下啟動失敗情況(系統啟動過程止步不前,但是也沒有明顯的報錯資訊。是以錄屏工具是有必要的)

Linux系統診斷小技巧(15):啟停問題之如何修複檔案系統損壞題外話回到話題如何修複問題?終焉

如何修複問題?

因為目前執行個體啟動失敗,這種情況下在目前執行個體上,我們沒有用shell來解決問題。是以,我們需要先解決在哪裡來修複的問題。

解決這個問題的方案比較多,運維人員常見的手段是使用LiveCD。這裡我們推薦使用快照的方式。具體使用請參考

的有關資訊。

配置錯誤

這種情況隻要把錯誤配置修改完畢即可解決問題,我們略過不談。

分區表丢失問題

修複方案的依據

分區表丢失,隻要重新建立分區表即可。因為分區表資訊隻涉及變更磁盤上第1個扇區指定位置的内容。是以,隻要确認有分區情況,在分區表丢失的情況下,重做分區是不會損壞磁盤上的資料的。但是分區起始位置和尺寸需要正确,否則不能解決問題。

分區的大小,因為大家(基本)都是一個磁盤分一個區,是以(幾乎)不用考慮分區大小(從檔案系統資訊是可以計算分區大小的)。起始位置确定後,大小選擇fdisk給出的就好。是以,問題的關鍵是如何确定分區的開始位置。

我們以常見的Ext檔案系統為例,具體請參看

如何從Ext3或者Ext4檔案系統推斷分區位置

重建分區

重建分區可以按照下面的步驟來實作。

确定分區起始位置

首先,我們需要先确認分區上的檔案系統資訊。這有多種方式:

  1. 檢視/etc/fstab和/etc/mtab配置檔案。
  2. 如果檔案系統還是挂載情形,則檢視/proc/mounts
  3. 直接檢查檔案系統魔數。
  4. 從系統日志追查。

我們看下直接檢查檔案系統魔數的例子,并用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

   裝置 Boot      Start         End      Blocks   Id  System
/dev/vdb1              56  2147483647  1073741796   83  Linux
[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 Boot      Start         End      Blocks   Id  System
/dev/vdb1            2048  2147483647  1073740800   83  Linux
[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: 

Number  Start  End          Size         Type     File system  Flags
 1      2048s  2147483647s  2147481600s  primary

#
# 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 ~]#           

終焉

祝探索愉快。

繼續閱讀