您的位置:首页 > 运维架构 > Linux

linux系统下备份多个根文件系统

2015-09-22 17:57 435 查看

linux系统下备份多个文件系统

在一些要求比较高的嵌入式系统中,要求做两个甚至三个系统,以防止在升级或者操作不当时候文件系统被损坏,从而这个设备就变砖啦。这个问题可以有两种比较好的方法解决。一是系统备份,也就是把根文件系统烧写到几个不同的分区,当一个分区损坏后,然后从备份的分区启动,这样可以有效的避免机器或者设备变砖,但是这也要求系统的存储要够大。二是在uboot里开发刷机程序,现在的android 手机基本上都支持,手持设备有这种方式还好,但是工业设备一般没有条件这样做,或者支持网口进入进行刷机,操作步骤有点繁琐。

我们的设备对这些电子芯片的价格不是很敏感,所以选择了第一种方式。

实现的功能

uboot根据启动的版本需求,引导linux内核,挂载Flash中相应版本根文件系统。

1) 能引导linux内核启动,挂载相应版本的根文件系统.

Uboot启动时根据EEPROM中的启动的版本标识,启动内核后,挂载相应版本的根文件系统。

2) 当前版本启动失败时,能自动回退到上一版本,上一版本无法启动时,继续退到原厂版本,原厂版本无法启动时则判断为设备损坏。

Uboot启动内核时,读取EEPROM中的启动版本分区标识,挂载相应版本的根文件系统,上电次数在uboot中自加1,运行次数会在系统启动之后的应用程序中自加,如果系统上电次数和运行次数相差超过三次,即系统启动三次不成功,此时更新启动版本标识为上一版本,回退到上一版本,如果回退到原厂版本也不能启动,则判断为设备损坏,无法启动。

运行环境

本系统运行的硬件环境是ARM最小系统,ARM芯片为AT91SAM9G20,本系统在ARM上运行linux操作系统。

EEPROM底层驱动开发简单说明

eeprom是一款采用I2C通信技术的存储芯片,uboot底层没有支持I2C通信的接口,需要自己开发或者移植,主要增加的两个文件为u-boot-1.3.4\cpu\arm926ejs\at91sam9下的i2c.c文件与u-boot-1.3.4\include下的at91sam9_i2c.h文件,这两个文件实现了与底层硬件的I2C通信。

实现了i2c_read()与i2c_write()两个函数的接口:

1. I2c_read()—从i2c设备中读数据函数格式如下:

int i2c_read (unsigned char chip, unsigned int addr, int alen,unsigned char *buffer, int len)

chip:芯片的物理地址,传入时一般需要右移一位

addr:内部存储器偏移地址

alen:偏移地址的长度

buffer:读出的数据存储区

len: 读出数据的长度

- 2. I2c_read()—从i2c设备中读数据函数格式如下:

int i2c_write(unsigned char chip, unsigned int addr, int alen,unsigned char *buffer, int len)

chip:芯片的物理地址,传入时一般需要右移一位

addr:内部存储器偏移地址

alen:偏移地址的长度

buffer: 写入数据的存储区

len: 写入数据的长度

i2c_read()与i2c_write()可以实现挂载总线上的所有i2c设备的通信。直接调用就可以。在Cmd_eeprom.c里有两个eeprom_read()与eeprom_write()两个函数,打开相关的宏后也可以直接使用,实际上就是调用了i2c_read()与i2c_write()两个函数,功能一样。

NandFlash 存储说明及规划

NandFlash数据位宽为8位,容量是256MB,划分了六大存储区,bootstrap、uboot与ubootEnv占用了前2M的存储空间为mtdblock0;Kernel单独一个存储空间占用2M为mtdblock1;后面有三个根文件系统与FPGA镜像文件存储区分别是rootfs/fpga,、rootfs/fpga1、rootfs/fpga2,占用的存储块为mtdblock2、mtdblock3、mtdblock4。最后一个为data分区,没有使用。

根据以上规划,kernel里的代码(在board-sam9g20ek.c文件里修改)分区更改如下:
static struct mtd_partition __initdata ek_nand_partition[] = {
{
.name   = "Bootstrap/uboot/",
.offset = 0,
.size   = SZ_2M,
},
{
.name   = "kernel",
.offset = MTDPART_OFS_NXTBLK,
.size   = SZ_2M,
},
{
.name   = "rootfs/fpga",
.offset = MTDPART_OFS_NXTBLK,
.size   = 30*SZ_1M,
},

{
.name   = "rootfs/fpga1",
.offset = MTDPART_OFS_NXTBLK,
.size   = 30*SZ_1M,
},
{
.name   = "rootfs/fpga2",
.offset = MTDPART_OFS_NXTBLK,
.size   = 30 * SZ_1M,
},

{
.name   = "data",
.offset = MTDPART_OFS_NXTBLK,
.size   = MTDPART_SIZ_FULL,
},
};


参数传递

在uboot里设置了3种CONFIG_BOOTARGS环境参数变量对应于kernel里的flash分区,默认配置参数为CONFIG_BOOTARGS,CONFIG_BOOTARGS1与CONFIG_BOOTARGS2为升级配置参数,它们只有根文件系统启动位置不同(mtdblock2、mtdblock3或者mtdblock4),其它参数配置一样。

#define CONFIG_BOOTARGS  "mem=64M console=ttyS0,115200
mtdparts=atmel_nand:2M(bootstrap/uboot/kernel)ro,2M(kernel)ro,\
30M(rootfs/fpga), 30M(rootfs/fpga1),30M(rootfs/fpga2), -(data) root=/dev/mtdblock2 rw rootfstype=jffs2"
#define CONFIG_BOOTARGS1 "mem=64M console=ttyS0,115200 mtdparts=atmel_nand:2M(bootstrap/uboot/kernel)ro,2M(kernel)ro,\
30M(rootfs/fpga), 30M(rootfs/fpga1),30M(rootfs/fpga2), -(data) root=/dev/mtdblock3 rw rootfstype=jffs2"
#define CONFIG_BOOTARGS2  "mem=64M console=ttyS0,115200 mtdparts=atmel_nand:2M(bootstrap/uboot/kernel)ro,2M(kernel)ro,\
30M(rootfs/fpga), 30M(rootfs/fpga1),30M(rootfs/fpga2), -(data) root=/dev/mtdblock4 rw rootfstype=jffs2"


功能实现

在uboot启动时,读取版本信息,上电次数以及运行次数等各种参数来判别要设置的传递给内核的参数,实现了版本的启动选择以及回退等功能,功能实现的
4000
代码在board.c文件的start_armboot()函数里实现。

通过
setenv("bootargs", CONFIG_BOOTARGS2);
来设置bootargs的环境变量,从而可以启动不同分区的系统。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息