標籤:串連 ini 資訊儲存 cat cpu 刪掉 command 手動 而且
背景:
Linux嵌入式裝置核心掛死後,無法自動重啟,需要手動重啟。而且如果當時沒有連串口的話,就無法記錄核心掛死時的堆棧,所以需要添加一種方式來記錄核心掛死資訊方便以後調試使用。裝置中增加kdump功能,可以將核心掛死的堆棧資訊記錄下來,供後期分析。
操作步驟:
1、添加kdump所需的程式及設定檔
方法:目前所分析得知需要如下檔案/sbin/kdump /sbin/kexec /bin/kdumpctl /etc/kdump.conf /etc/sysconfig/kdump,然後編輯etc目錄下的兩個設定檔;修改kdump中KDUMP_BOOTDIR="/mnt",KDUMP_COMMANDLINE_APPEND="1 irqpoll maxcpus=1",KDUMP_IMG="kernel.img";修改kdump.conf內容為path /mnt/workdir/log;還需要修改kdumpctl中有關kdump和kexec的路徑;將這些檔案放到裝置的mnt目錄下然後重啟,重啟後執行kexec -l /mnt/kernel.img --initrd=/mnt/rootfs.img --command-line="`cat /proc/cmdline` 1 irqpoll maxcpus=1";kexec -e 查看是否添加成功。
2、問題:各種工具、設定檔均添加成功,但是執行kdumpctl start命令時,依然報錯 BUG: unable to handle kernel paging request at ffff880001497000,或者不列印堆棧資訊直接提示killed。
解決方案:經過測試,將添加到grub.cfg中的[email protected]改成crashkernel=128M,完全省略“@Y”這一部分,這樣,kernel 會為我們自動選擇一個起始地址。這樣就不會出現起始地址錯誤等問題了。在測試kexec時,最好加上-d選項,將debug資訊列印出來。
3、問題:經測試,按照第二步中的操作方法,kexec -e執行完成後,核心打完堆棧之後並未重啟,而是直接卡死了。
解決方案:分析之後才發現,因為在/etc/sysconfig/kdump設定檔KDUMP_COMMANDLINE_APPEND欄位添加了reset_devices,所以導致kdump核心無法重啟。將KDUMP_COMMANDLINE_APPEND選項內容中reset_devices這個值刪掉就可以了。
4、問題:核心panic錯誤發生後,核心重啟,但是只進入到了新解壓後的rootfs中,而系統的inittab根本就未被執行,導致後續的指令碼沒有執行。
解決方案:經過尋找相關資料發現,linux在核心載入完成後,會解壓initrd成rootfs根檔案系統,隨後執行根檔案系統中的linuxrc或者init來初始化inittab設定檔,然後進行一系列的指令碼初始化操作。根據現象發現,inittab確實沒有被執行過,所以就開始尋找inittab未被執行的原因。然後修改/etc/sysconfig/kdump檔案中的KDUMP_COMMANDLINE_APPEND的值為"1 irqpoll maxcpus=1 init=/linuxrc",然後就可以執行成功了。
5、問題:由於採用原有的rootfs會造成裝置啟動許多不必要的程式、服務,所以應該重新定製一個kdump專用的rootfs。
解決方案:下載新版的busybox,然後編譯、安裝產生_install目錄,該目錄下就是部分檔案系統,然後在建立dev,etc,lib,lib64,var,proc,tmp,mnt,sys這些系統所需的目錄以及裝置所需的workdir,mnt目錄。由於編譯busybox時,採用靜態編譯出錯,所以沒有採用靜態編譯的方式,因而需要用ldd busybox查看busybox所需的動態庫,然後將這些動態庫拷貝到建立好的/lib64目錄中。由於linuxrc需要初始化系統,因而需要在/etc目錄下添加fstab、inittab以及init.d/rcS這三個必備檔案,由於fstab和inittab只跟系統有關,所以可以借用原來rootfs的對應檔案,rcS系統程式的初始化指令碼,可以將自己所需要實現的命令添加到rcS中,還需要在dev目錄中添加相關裝置節點,用mknod命令添加console, null等裝置以及shm,pts目錄作為掛載點。由於kdump重啟後的系統中產生的vmcore過大,CF卡儲存不下,只能用vmcore-dmesg /proc/vmcore命令提取核心崩潰日誌,所以rcS就簡單實現了掛載檔案系統、CF卡、提取核心崩潰資訊,然後重啟系統的功能。由於新的rootfs是在kdump過程中使用,與原有的rootfs獨立,所以提取核心崩潰日誌的相關程式就需要預先添加到新的rootfs相關的目錄中。整個rootfs目錄檔案添加完成之後,就在_install目錄下執行find . | cpio -H newc --quiet -o | gzip -9 >~/rootfs.img,將這些檔案夾打包並壓縮產生rootfs.img放到目前使用者的home目錄。
6、問題:kdumpctl啟動kdump服務時,要求核心以及initrd的名稱格式,而且需要修改boot.cfg啟動設定檔。
解決方案:最開始向採用修改安裝包的方式,向安裝包中添加kdump需要的核心以及initrd檔案,但是經過嘗試無法將這些檔案打到vsos.bin中,後來發現是package.ini檔案的配置,修改package.ini的配置後,可以將對應的檔案添加到vsos.bin中了。但是在裝置安裝的時候,依然沒有安裝新添加的檔案。由於對裝置解包安裝的過程不太熟悉,所以就採取折衷的方式:將新的initrd(即kdump需要的rootfs檔案)添加到/mnt/system目錄下,然後在開機啟動指令碼start.sh中,添加修改boot.cfg的功能,並將新的rootfs檔案移至/mnt目錄下,同時建立一個對原有核心檔案的軟串連供kdump使用,由於kdumpctl會檢查核心檔案、initrd檔案、以及kdump的設定檔的時間戳記,如果initrd檔案的時間戳記早於其他檔案,kdumpctl嘗試重建initrd檔案,這個過程中很有可能報錯,所以在移動檔案結束後,就會用touch命令更新initrd檔案的時間到最新。
7、問題:CF卡的磁碟編號有時不是/dev/sda1,導致kdump重啟後按照/dev/sda1掛載失敗
解決方案:用這個命令fdisk -l | grep "83" | grep "\*" | grep dev | awk ‘{print $1}‘來擷取CF卡的裝置號。
內容匯總
kexec -l選項是直接載入核心,然後配置kexec -e命令啟動新核心;而kexec -p選項則是指明當前核心遇到panic時,要啟用的核心。需要echo c>/proc/sysrq-trigger,手動觸發核心panic。
其實完全可以用kexec取代kdumpctl,這樣就可以直接用老的核心名稱,而且也不用考慮對kernel、initrd及設定檔的時間戳記問題,而且由於採用的是新的rootfs系統,通過修改rcS指令碼自己手動實現的核心崩潰資訊儲存,完全可以脫離對kdump相關設定檔的依賴,這樣做是最簡單的。但是考慮到標準linux中啟動kdump的方式相容,方便後續人員維護,就採用了kdumpctl的方式啟動kdump服務。
由於在svn上提交的是一個封裝好的img檔案,所以要想對修改img檔案中的內容,則需要先將img檔案拷貝到一個新的檔案夾下,然後執行:mv rootfs.img rootfs.img.gz; gzip -d rootfs.img.gz; cpio -id 還原出整個檔案系統,然後按照需求進行修改,隨後執行find . | cpio -H newc --quiet -o | gzip -9 >~/rootfs.img重建img檔案。上述重建img檔案的命令中,最後img檔案的位置不能在目前的目錄。
得失分析:
由於對核心相關內容不太熟悉,所以前期只能通過從網上找相關資料,一點點嘗試。雖然這個過程難了點兒,但是自己從中還是學到了很多東西,諸如Linux啟動過程的詳細過程之類的,學會了裁剪核心以及busybox,可以搭建一個小的迷你linux。
由於時間限制,並未進一步實現提取vmcore的功能。不過在現在有工作的基礎之上應該很容易添加擷取vmcore的功能。
手動添加kdump