*******设计可靠的env存储区(WS_ENV)
*** 使用环境
在嵌入式系统中,bootloader与linux kernel都需要互相传递变量,例如在bootloader中设
置IP地址,在kernel中读取IP地址。如果让boot loader直接写linux的文件系统,bootloader
将会变得非常大,一般都使用环境变量实现变量的传递。
*** 算法设计
通过研究发现,env使用的是字符串,而且flash的特点是由1变0容易,由0变1需要重新擦除。
可以顺序的按照tag value把env存储于flash中,例如:
⊙代表结束符”/0”.
原始存储区orig:tag1⊙val1⊙tag2⊙val2⊙tag3⊙val3⊙剩余位置
a. 增加操作ws_setenv:
从orig增加一个tag4时,在结尾处增加,如:
tag1⊙val1⊙tag2⊙val2⊙tag3⊙val3⊙tag4⊙val4⊙剩余位置
从orig增加tag4的值为空字符串时,如下:
tag1⊙val1⊙tag2⊙val2⊙tag3⊙val3⊙tag4⊙⊙剩余位置
当剩余位置到达了env所在的块的结尾位置,则需要整理(defrag):
将整块擦除,然后再从内存中的控制结构中写入所有的tag,下面会详述控制结构。
为了保证擦除整块env后,突然断电,不会造成数据丢失,需要有一个备份env块。
擦除前将env拷贝到备份env后,再擦除env。
b. 删除操作ws_unsetenv:
从orig删除一个tag1时,将对应的tag1与val全部变为⊙(因为1变0容易)。如:
⊙⊙⊙⊙⊙⊙⊙⊙⊙⊙tag2⊙val2⊙tag3⊙val3⊙剩余位置
c. 修改操作ws_setenv:
从orig修改tag1, 让其值变为changed,将实行删除后,再增加操作.如:
⊙⊙⊙⊙⊙⊙⊙⊙⊙⊙tag2⊙val2⊙tag3⊙val3⊙tag1⊙changed⊙剩余位置
通过上述算法,可以设计出env的排列结构如下:
若env块的前4个字节为“good”表示env存储区未损坏,不需要从备份区拷贝数据。否
则需要擦除env,然后从备份区拷贝(64k-4)的数据。
相应的内存数据结构设计如下所示。
d. recovery env algorithm:
1. 如果backup env的magic有效,从backup env中拷贝数据到env。数据拷贝完后,
擦除backup env block。
2. 当前env的数据存储满后,先把当前env的所有数据存储到backup env中,然后
擦除env,再把内存中的数据写入env区。写完后,写入env magic, 然后擦除
backup env block.
分析:这里需要考虑极端情况:假设当前系统env已满,但defrag后剩余的空间
只有一点点, 那么,例如设置一个相同tag的值时,首先找到env,然后设置为⊙,
然后defrag,仅回收刚才设置为⊙的空间,这样会照成每设几个env,就要defrag,
实在不划算。因此建议判断是否需要defrag的条件改为:
当前系统有效空间+env值小于env size-4k。如果不满足,则直接返回空间已满。
***Hash设计
为了提高查找效率,需要设计好的hash算法,对于env来说,字符串,让每个字母相加,
得到的值再对hash表的大小取余,得到的位置就是env要插入的链表位置。
*** 数据结构设计
/* 每个env变量的结构 */
struct env_entry
{
struct env_entry *next; /* pointer to next entry */
unsigned int tag_offset; /* Offset in the env block */
char *tag_name;
char *tag_val;
};
/* 整个env的控制区 */
struct env_info
{
unsigned int base_addr; /* env base address, must start from a new block */
unsigned int env_size; /* env size, include backup env sector */
unsigned int block_size; /* memory block size, in byte */
unsigned int env_valid_size;/* valid env entrys size */
unsigned int free_offs; /* Offset from base_addr */
unsigned int numEntrys; /* number of env entrys */
struct env_entry **hash_bucket;
void *priv; /* private data, use it whateven you like */
struct semaphore env_lock; /* big lock */
int (*ws_hash)(char *name); /* hash function */
int (*load_env)(struct env_info *info); /* load env from memory */
int (*erase)(struct env_info *info, unsigned addr, unsigned len); /* erash method */
int (*read)(struct env_info *info, unsigned from, unsigned len, char *buf); /* read method */
int (*write)(struct env_info *info, unsigned to, unsigned len, char *buf); /* write method */
};
*** 代码实现
ws_env.h
ws_env.c
ws_env_linux.