題外話
我們先講什麼是檔案系統和需要的工具。
檔案系統
現在的存儲種類衆多、堆棧繁雜。但是使用者直接的接口還是
。對于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. 配置系統啟動挂載建立檔案系統
現在重新開機系統,驗證挂載情況
可見挂載是成功的。
損壞測試: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
裝置 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 ~]#
終焉
祝探索愉快。