文獻標識碼: A
文章編號: 0258-7998(2015)03-0024-04
0 引言
盡管Linux作為嵌入式操作系統有著諸多的優勢,但是由于嵌入式操作系統自身的特點,如嵌入式應用范圍的多樣性和復雜性,導致嵌入式產品維護難度大的問題更加突出。嵌入式系統在實際環境中投入運行后,掉電等意外的災難、用戶錯誤或惡意地對數據進行修改和刪除、一部分無法在開發中充分測試的錯誤等都會導致功能失效,嚴重的可能導致系統癱瘓。如果采用人工更新方式,由于安裝位置等因素有時會不方便。因此,嵌入式系統的自動備份與恢復機制是恢復數據最容易和最有效的保證方法[1],并逐漸成為嵌入式系統實際應用中的一個重要問題。
目前,普遍使用雙機熱備份[2]、容災備份[3]等技術做為實現嵌入式系統高可靠性的設計方案,由于采用獨立的兩套系統,因此增加了一定的設計難度和成本[4]。本文針對當前嵌入式系統備份技術存在的一些問題,通過分析嵌入式U-Boot及Linux內核,將嵌入式系統鏡像在一套設備上備份為多份,每次僅有一個系統運行。當運行的操作系統出現故障時,就會觸發系統備份恢復機制,使用下一個可用的備份分區覆蓋掉出現故障的系統分區,然后啟動下一個可用的系統。整個系統不需要備用設備,大大地節約了成本和功耗,提高了系統的穩定性和可靠性。
1 系統總體方案設計
1.1 系統總體設計
嵌入式Linux系統中的備份與恢復總體實現方案如圖1所示。
該系統由x-loader(SPL)、U-Boot、U-Boot Env、Judge-
Area、Kernel(uImage)和Rootfs(ubi.img)六部分組成。mtd是同一NAND Flash上劃分出的不同分區,并且uImage和ubi.img在設備上備份了多份,系統各組成部分特性及作用介紹如下:
(1)x-loader是一級引導程序[5],U-Boot是二級引導程序[6],U-Boot Env存儲內核啟動參數。
(2)Judge-Area存儲系統備份及恢復參數。在U-Boot和Linux下可以共享訪問。
(3)Kernel是Linux內核[7],Rootfs采用開源的無排序區塊圖像文件系統UBIFS(Unsorted Block Image File System),特別適用于嵌入式系統[8]。
A、B、C均為系統鏡像區,存放內核和文件系統。U-Boot通過判斷Judge-Area中的參數,啟動其中一個系統鏡像區,并將啟動過程中的故障情況反饋給Judge-Area。當系統運行出現故障或者崩潰時,使用watchdog機制來使其硬件復位,通過U-Boot下的自動備份恢復機制,用其他可運行的備份來覆蓋出現故障的系統鏡像區,確保能啟動一個可用系統。
目前運行Linux系統的NAND Flash配置都比較大,而裁剪后的內核和精簡的UBI文件系統實際占用不到20 MB容量,或者更少[9]。因此,這為實現Linux系統的多重備份提供了可能。
1.2 備份及恢復機制
下面以三重備份與恢復為例來說明系統的備份及恢復流程,整個系統鏡像分3個地方保存在NAND Flash,具體的過程如下:
(1)系統上電或復位U-Boot啟動運行,假設A區相關的r_active_1(引導標志)和b_success_1(內核啟動成功標志)為“yes”,BC區域均為“no”。在系統鏡像未成功啟動以前的過程可以認為是啟動失敗的,所以先設置A區r_active_1、b_success_1為“no”,rec_kernel_1(內核恢復標志)、rec_fs_1(文件系統恢復標志)為“yes”。還要設置B區r_active_2、b_success_2為“yes”。
(2)然后U-Boot加載A區域的系統,若Linux系統運行正常,則在Linux下還原所有標志值為初始值。若引導失敗,則若干時間后觸發watchdog復位系統,此時U-Boot再次運行,判斷b_success_1為“no”,表示上次引導失敗,并且rec_kernel_1、rec_fs_1為“yes”,表示需要將B區的內核及文件系統覆蓋到A區,覆蓋成功后清除恢復標志和重置b_success_1,再通過watchdog復位系統。
(3)U-Boot判斷r_active_2、b_success_2為“yes”,故選擇啟動B區域的系統。在系統啟動成功以前,設置B區r_active_2、b_success_2為“no”,rec_kernel_2、rec_fs_2為“yes”,還要設置C區r_active_3為“yes”。
(4)加載B區域的系統,若Linux系統能正常運行,則在Linux下還原所有標志為初始值。如果B區也失敗了,復位系統,在U-Boot下用C區覆蓋B區域。覆蓋成功后清除恢復標志和重置b_success_2,再通過watchdog復位系統。同理,再從C區域的系統啟動,當C區域也出現問題后,則重新從A區域啟動,循環依次選擇。
2 系統實現
2.1 Judge-Area基礎設計
Judge-Area是在NAND Flash上劃分出的單獨區域,內部存儲系統備份及恢復的環境參數,該區類似U-Boot Env區域。
為了能在U-Boot下查看和修改這些參數,將本區域的所有參數定義在一個judge_tab數組中,然后導入到哈希表judge_htab中。
struct hsearch_data judge_htab;
himport_r(&judge_htab, (char *)judge_tab, \
sizeof(judge_tab), ′\0′, 0)
為方便調試和實現手動進行備份恢復操作,添加U-Boot下串口打印命令printjudge,修改命令setjudge,保存命令savejudge。打印命令printjudge的實現為:
/* print a single name */
hsearch_r(e, FIND, &ep, &judge_htab);
/* print whole list */
len=hexport_r(&judge_htab, ′\n′, &res, 0);
同理,修改命令setjudge也是對judge_htab的簡單操作,由于這些修改只是對內存上的數值進行操作,所以修改后的值沒有保存在NAND Flash中。保存命令savejudge便是對這些變量進行存儲,存儲的過程如下:使用hexport_r將數據導出到新的哈希表judge_htab_new,然后調用nand_erase_opts擦除Judge-Area區域,最后使用nand_write將數據寫入到該區域。為提高讀寫數據的可靠性,開啟硬件壞塊檢測、ECC校驗。
2.2 U-Boot下備份及恢復設計
U-Boot下備份及恢復機制設計如圖2所示。
函數judge_get()實際上調用hsearch_r函數查詢哈希表judge_htab,從Judge-Area讀取下一個系統鏡像的地址addr_x及大小size_x。
函數img_recover()的功能是調用img_read、img_write恢復下一個系統鏡像到當前系統鏡像區。
Judge-Area參數重置函數judge_reset()主要工作是調用setjudge分別設置b_success_x為"yes",設置rec_fs_x、rec_kernel_x為"no"。
U-Boot Env參數重置函數uEnv_reset()的工作是調用setenv設置nand_src_addr、nand_img_siz、nand_root對應為"n_kaddr_x"、"n_ksize_x"、"ubi0:rootfs rw ubi.mtd=y,2048"。其中,setenv為U-Boot自帶的函數[10],y(y=2*x+6)為文件系統所在分區。
參數預處理函數judge_init()主要工作是調用setjudge分別設置r_active_x、b_success_x為"no",設置rec_kernel_x、rec_fs_x、r_active_y、b_success_y為"yes"。其中,y=cyc_add(x),函數cyc_add()為周期相加函數,即當x<MAX_MTD_SYSTEM(系統鏡像區數量)時,x++,否則x=1。
2.3 Linux下備份及恢復設計
在系統鏡像啟動之前,U-Boot已經修改了Judge-Area中的參數并保存到NAND Flash,那么,Linux下就是對這些參數進行后期處理。本文采用開機自啟動腳本方式實現參數的處理[11],針對實際的應用環境,可以將腳本插入到“不信任”位置。一旦系統或程序崩潰,腳本就會接收到由應用程序、內核等傳來的命令。然后決定是進行參數還原,還是復位系統。Linux下備份及恢復機制主要就是通過該腳本實現,如圖3所示。
本文使用MTD+UBIFS的方式管理Flash,跳過FTL/NFTL(Flash轉換層/NAND Flash轉換層),大大提高了管理能力[12]。借用mtd-utils工具包中針對NAND操作的工具[13],可以將Judge-Area(mtd6)區中的內容保存到judge.txt文件中。然后調用Linux下的sed命令修改標志位,最后將修改后的文件寫回到Judge-Area區。整個操作由anti_judge_init腳本完成,主要工作如下:
mtd_debug read /dev/mtd6 0 $filesize judge.txt
/* 修改參數old_flag為new_flag */
sed -e "s/$old_flag/$new_flag/g" judge.txt
mtd_debug erase /dev/mtd6 0 $filesize
mtd_debug read /dev/mtd6 0 $filesize judge.txt
為保證NAND分區一致性,需要修改內核NAND partition信息。內核分區信息存放在mtd_partition結構體中,該文件一般位于arm/arm/plat目錄下。另外,制作UBIFS文件系統也要和內核分區保持一致。制作UBIFS鏡像文件,需要使用mkfs.ubifs工具,該工具也是mtd-utils工具包中的內容[14]。
3 系統測試
本系統在多款開發板上測試通過,以Tiny210開發板上的三重備份與恢復系統為例,測試方法是重新編譯包含自動備份與恢復機制的u-boot.img、uImage和ubi.img。ubi.img中加入了視頻監控程序,在該程序中預留運行一段時間攝像頭就會打開失敗的BUG。因此,視頻監控程序就是本系統“不信任”位置,如果程序運行失敗,就執行Linux下的自動備份與恢復機制。Tiny210開發板集成了512 MB SLC NAND Flash,將NAND Flash被分成12個區域,見表1。
進入SD卡上的U-Boot,運行updatesys將生成的u-boot.img、uImage、ubiubi.img燒寫到指定區域。上電,系統啟動成功,運行視頻監控程序一段時間后,系統自動重啟,在串口上查看到的備份與恢復信息如圖4所示。
從打印的信息可以看出,A區的系統鏡像被B區覆蓋,接著運行另一個分區的系統鏡像。
4 結論
從測試結果看,本文設計的備份與恢復機制可以保證系統能在特殊的環境下穩定地工作,整個過程都是系統自動完成,維護方便。目前,NAND Flash的成本越來越低,容量越來越大[15],這種備份與恢復方法無疑是降低成本、保證系統穩定性方便有效的方法。該方案可以應用在一些對功能穩定性要求高和維護不方便的系統測試等場合。
參考文獻
[1] 索紅軍.嵌入式系統中熱備份雙機切換技術研究[J].微計算機信息,2008,24(8):32-34.
[2] 馬錦榮.一種嵌入式系統bootrom自動備份及切換技術[J].單片機與嵌入式系統應用,2011,11(12):74-75.
[3] 謝長生,韓德志,李懷陽.容災備份的等級和技術[J].中國計算機用戶,2003,19(18):30-31.
[4] 郭榮佐,黃君.嵌入式實時控制系統硬件可靠性及應用研究[J].電子技術應用,2012(5):11-14.
[5] 蔡利平,任家富,童銳,等.基于ARM的Nand Flash啟動分析與移植[J].計算機工程與設計,2012(3):931-935.
[6] 高文輝,師奕兵,張偉.基于S3C2440的U-Boot雙啟動實現[J].測控技術,2012(2):87-91.
[7] 胡勇其,侯紫峰.嵌入式Linux下NAND存儲系統的設計與實現[J].計算機工程,2006(4):61-63,81.
[8] 韋斯,丁志剛,張偉宏.LINUX下UBI子系統的研究與應用[J].計算機應用與軟件,2010(10):68-71.
[9] 賈源泉,肖儂,賴明澈,等.基于NAND FLASH的多路并行存儲系統中壞塊策略的研究[J].計算機研究與發展,2012(z1):68-72.
[10] 武貝貝.面向NAND閃存的SQLite數據恢復技術研究與應用[D].浙江:杭州電子科技大學,2012.
[11] 陳鵬,王樹志,董孝峰,等.一種嵌入式操作系統休眠喚醒后程序自動運行的方法[J].電子技術應用,2012,38(2):11-13.
[12] 張少波,徐廣輝,田小鋒,等.基于Nand FLASH高可靠自恢復實時文件系統[J].計算機工程與科學,2012(6):169-173.
[13] 高麗,張歡慶.嵌入式Linux中NAND Flash設備驅動研究[J].電腦開發與應用,2014(5):11-16.
[14] 鞠高明,俞建新.UBIFS閃存文件系統分析與研究[J].電腦知識與技術,2014(4):749-754.
[15] 魯慧榮.2012年閃存技術與市場變化趨勢[J].集成電路應用,2013(1):4-6.