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