【完善】flash 状态更新功能及自动恢复功能。

Signed-off-by: armink <armink.ztl@gmail.com>
pull/42/head
armink 7 years ago
parent 47563b0e73
commit 4028c93e75

@ -239,10 +239,10 @@ static EfErrCode write_status(uint32_t addr, uint8_t status_table[], size_t stat
set_status(status_table, status_num, status_index); set_status(status_table, status_num, status_index);
#if (EF_WRITE_GRAN == 1) #if (EF_WRITE_GRAN == 1)
byte_index = status_index / 8; byte_index = (status_index - 1) / 8;
result = ef_port_write(addr + byte_index, (uint32_t *)&status_table[byte_index], 1); result = ef_port_write(addr + byte_index, (uint32_t *)&status_table[byte_index], 1);
#else /* (EF_WRITE_GRAN == 8) || (EF_WRITE_GRAN == 32) || (EF_WRITE_GRAN == 64) */ #else /* (EF_WRITE_GRAN == 8) || (EF_WRITE_GRAN == 32) || (EF_WRITE_GRAN == 64) */
byte_index = (status_num - 1 - status_index) * (EF_WRITE_GRAN / 8); byte_index = (status_index - 1) * (EF_WRITE_GRAN / 8);
/* write the status by write granularity /* write the status by write granularity
* some flash (like stm32 onchip) NOT supported repeated write before erase */ * some flash (like stm32 onchip) NOT supported repeated write before erase */
result = ef_port_write(addr + byte_index, (uint32_t *) &status_table[byte_index], EF_WRITE_GRAN / 8); result = ef_port_write(addr + byte_index, (uint32_t *) &status_table[byte_index], EF_WRITE_GRAN / 8);
@ -255,7 +255,7 @@ static size_t read_status(uint32_t addr, uint8_t status_table[], size_t total_nu
{ {
EF_ASSERT(status_table); EF_ASSERT(status_table);
ef_port_read(addr, (uint32_t *) status_table, total_num); ef_port_read(addr, (uint32_t *) status_table, STATUS_TABLE_SIZE(total_num));
return get_status(status_table, total_num); return get_status(status_table, total_num);
} }
@ -292,9 +292,6 @@ static uint32_t get_next_env_addr(sector_meta_data_t sector, env_meta_data_t pre
static EfErrCode read_env(env_meta_data_t env) static EfErrCode read_env(env_meta_data_t env)
{ {
//TODO 计算下一个节点的地址,注意考虑越界
//TODO 读取节点的各个元数据
//TODO 检查 CRC32 是否正确
struct env_hdr_data env_hdr; struct env_hdr_data env_hdr;
uint8_t buf[32]; uint8_t buf[32];
uint32_t calc_crc32 = 0, crc_data_len, env_name_addr; uint32_t calc_crc32 = 0, crc_data_len, env_name_addr;
@ -420,11 +417,12 @@ static void env_iterator(env_meta_data_t env, void *arg1, void *arg2,
struct sector_meta_data sector; struct sector_meta_data sector;
uint32_t sec_addr; uint32_t sec_addr;
//TODO 支持从缓存中进行遍历 //TODO 支持通过 using_sec_table 遍历
sector.addr = GET_NEXT_FAILED; sector.addr = GET_NEXT_FAILED;
/* search all sectors */ /* search all sectors */
while ((sec_addr = get_next_sector_addr(&sector)) != GET_NEXT_FAILED) { while ((sec_addr = get_next_sector_addr(&sector)) != GET_NEXT_FAILED) {
//TODO 检查所有扇区的剩余空间,是否有合适的扇区,优先 using_sec_table
if (read_sector_meta_data(sec_addr, &sector, false) != EF_NO_ERR) { if (read_sector_meta_data(sec_addr, &sector, false) != EF_NO_ERR) {
continue; continue;
} }
@ -523,12 +521,31 @@ static EfErrCode write_env_hdr(uint32_t addr, env_hdr_data_t env_hdr) {
return result; return result;
} }
static uint32_t get_next_env_addr_by_size(sector_meta_data_t sector, size_t env_size)
{
uint32_t sec_addr;
/* search all sectors */
sector->addr = GET_NEXT_FAILED;
while ((sec_addr = get_next_sector_addr(sector)) != GET_NEXT_FAILED) {
//TODO 检查所有扇区的剩余空间,是否有合适的扇区,优先 using_sec_table
if (read_sector_meta_data(sec_addr, sector, true) != EF_NO_ERR) {
continue;
}
/* sector has space */
if (sector->remain > env_size) {
return sector->empty_env;
}
}
return GET_NEXT_FAILED;
}
static EfErrCode create_env_blob(const char *key, const void *value, size_t len) static EfErrCode create_env_blob(const char *key, const void *value, size_t len)
{ {
EfErrCode result = EF_NO_ERR; EfErrCode result = EF_NO_ERR;
struct env_hdr_data env_hdr; struct env_hdr_data env_hdr;
static struct sector_meta_data sector; static struct sector_meta_data sector;
uint32_t sec_addr; uint32_t env_addr;
if (strlen(key) > EF_ENV_NAME_MAX) { if (strlen(key) > EF_ENV_NAME_MAX) {
EF_INFO("Error: The ENV name length is more than %d\n", EF_ENV_NAME_MAX); EF_INFO("Error: The ENV name length is more than %d\n", EF_ENV_NAME_MAX);
@ -545,17 +562,9 @@ static EfErrCode create_env_blob(const char *key, const void *value, size_t len)
return EF_ENV_FULL; return EF_ENV_FULL;
} }
sector.addr = GET_NEXT_FAILED; if ((env_addr = get_next_env_addr_by_size(&sector, env_hdr.len)) != GET_NEXT_FAILED) {
/* search all sectors */
while ((sec_addr = get_next_sector_addr(&sector)) != GET_NEXT_FAILED) {
//TODO 检查所有扇区的剩余空间,是否有合适的扇区,优先 using_sec_table
if (read_sector_meta_data(sec_addr, &sector, true) != EF_NO_ERR) {
continue;
}
/* sector has space */
if (sector.remain > env_hdr.len) {
size_t align_remain; size_t align_remain;
uint32_t env_addr = sector.empty_env; uint32_t sec_addr = EF_ALIGN_DOWN(env_addr, SECTOR_SIZE);
/* change the sector status to SECTOR_STORE_USING */ /* change the sector status to SECTOR_STORE_USING */
if (result == EF_NO_ERR) { if (result == EF_NO_ERR) {
uint8_t status_table[STORE_STATUS_TABLE_SIZE]; uint8_t status_table[STORE_STATUS_TABLE_SIZE];
@ -602,14 +611,12 @@ static EfErrCode create_env_blob(const char *key, const void *value, size_t len)
result = write_status(env_addr, env_hdr.status_table, ENV_STATUS_NUM, ENV_WRITE); result = write_status(env_addr, env_hdr.status_table, ENV_STATUS_NUM, ENV_WRITE);
} }
//TODO 更新 using_sec_table //TODO 更新 using_sec_table
break;
}
} }
return result; return result;
} }
static EfErrCode del_env(const char *key, env_meta_data_t old_env, bool pre_del) { static EfErrCode del_env(const char *key, env_meta_data_t old_env, bool complete_del) {
EfErrCode result = EF_NO_ERR; EfErrCode result = EF_NO_ERR;
uint32_t dirty_status_addr; uint32_t dirty_status_addr;
@ -631,7 +638,7 @@ static EfErrCode del_env(const char *key, env_meta_data_t old_env, bool pre_del)
} }
} }
/* change and save the new status */ /* change and save the new status */
if (pre_del) { if (!complete_del) {
result = write_status(old_env->addr.start, status_table, ENV_STATUS_NUM, ENV_PRE_DELETE); result = write_status(old_env->addr.start, status_table, ENV_STATUS_NUM, ENV_PRE_DELETE);
} else { } else {
result = write_status(old_env->addr.start, status_table, ENV_STATUS_NUM, ENV_DELETED); result = write_status(old_env->addr.start, status_table, ENV_STATUS_NUM, ENV_DELETED);
@ -666,7 +673,7 @@ EfErrCode ef_del_env(const char *key)
/* lock the ENV cache */ /* lock the ENV cache */
ef_port_env_lock(); ef_port_env_lock();
result = del_env(key, NULL, false); result = del_env(key, NULL, true);
/* unlock the ENV cache */ /* unlock the ENV cache */
ef_port_env_unlock(); ef_port_env_unlock();
@ -698,12 +705,12 @@ EfErrCode ef_set_env(const char *key, const char *value)
ef_port_env_lock(); ef_port_env_lock();
if (value == NULL) { if (value == NULL) {
result = del_env(key, NULL, false); result = del_env(key, NULL, true);
} else { } else {
env_is_found = find_env(key, &env); env_is_found = find_env(key, &env);
/* prepare to delete the old ENV */ /* prepare to delete the old ENV */
if (env_is_found) { if (env_is_found) {
result = del_env(key, &env, true); result = del_env(key, &env, false);
} }
/* create the new ENV */ /* create the new ENV */
if (result == EF_NO_ERR) { if (result == EF_NO_ERR) {
@ -711,7 +718,7 @@ EfErrCode ef_set_env(const char *key, const char *value)
} }
/* delete the old ENV */ /* delete the old ENV */
if (env_is_found && result == EF_NO_ERR) { if (env_is_found && result == EF_NO_ERR) {
result = del_env(key, &env, false); result = del_env(key, &env, true);
} }
} }
@ -799,18 +806,18 @@ __exit:
static bool print_env_cb(env_meta_data_t env, void *arg1, void *arg2) static bool print_env_cb(env_meta_data_t env, void *arg1, void *arg2)
{ {
uint8_t buf[32];
bool value_is_str = true, print_value = false; bool value_is_str = true, print_value = false;
size_t *using_size = arg1; size_t *using_size = arg1;
if (env->crc_is_ok) { if (env->crc_is_ok) {
/* calculate the total using flash size */ /* calculate the total using flash size */
*using_size += sizeof(uint32_t) + env->len; *using_size += env->len;
/* check ENV */ /* check ENV */
if (env->status == ENV_WRITE) { if (env->status == ENV_WRITE) {
ef_print("%.*s=", env->name_len, env->name); ef_print("%.*s=", env->name_len, env->name);
if (env->value_len < EF_STR_ENV_VALUE_MAX_SIZE ) { if (env->value_len < EF_STR_ENV_VALUE_MAX_SIZE ) {
uint8_t buf[32];
__reload: __reload:
/* check the value is string */ /* check the value is string */
for (size_t len = 0, size = 0; len < env->value_len; len += size) { for (size_t len = 0, size = 0; len < env->value_len; len += size) {
@ -885,6 +892,32 @@ static EfErrCode env_auto_update(void)
} }
#endif /* EF_ENV_AUTO_UPDATE */ #endif /* EF_ENV_AUTO_UPDATE */
static EfErrCode copy_env(uint32_t from, uint32_t to, size_t env_len)
{
EfErrCode result = EF_NO_ERR;
uint8_t status_table[ENV_STATUS_TABLE_SIZE];
result = write_status(to, status_table, ENV_STATUS_NUM, ENV_PRE_WRITE);
if (result == EF_NO_ERR) {
uint8_t buf[32];
for (size_t len = 0, size = 0; len < env_len; len += size) {
if (len + sizeof(buf) < env_len) {
size = sizeof(buf);
} else {
size = env_len - len;
}
ef_port_read(from + ENV_LEN_OFFSET + len, (uint32_t *) buf, size);
result = ef_port_write(to + ENV_LEN_OFFSET + len, (uint32_t *) buf, size);
if (result != EF_NO_ERR) {
return result;
}
}
result = write_status(to, status_table, ENV_STATUS_NUM, ENV_WRITE);
}
return result;
}
/** /**
* Check and load the flash ENV meta data. * Check and load the flash ENV meta data.
* *
@ -893,7 +926,7 @@ static EfErrCode env_auto_update(void)
EfErrCode ef_load_env(void) EfErrCode ef_load_env(void)
{ {
EfErrCode result = EF_NO_ERR; EfErrCode result = EF_NO_ERR;
uint32_t addr; uint32_t sec_addr, env_addr;
struct sector_meta_data sector; struct sector_meta_data sector;
struct env_meta_data env; struct env_meta_data env;
@ -904,13 +937,15 @@ EfErrCode ef_load_env(void)
//TODO 检查是否存在未完成的垃圾回收工作,存在则继续整理 //TODO 检查是否存在未完成的垃圾回收工作,存在则继续整理
//TODO 装载环境变量元数据using_sec_table //TODO 装载环境变量元数据using_sec_table
/* read all sectors */ /* read all sectors */
for (addr = env_start_addr; addr < env_start_addr + ENV_AREA_SIZE; ) { for (sec_addr = env_start_addr; sec_addr < env_start_addr + ENV_AREA_SIZE; ) {
/* check sector header */ /* check sector header */
result = read_sector_meta_data(addr, &sector, false); result = read_sector_meta_data(sec_addr, &sector, false);
if (result!= EF_NO_ERR) { if (result!= EF_NO_ERR) {
EF_INFO("Warning: ENV CRC check failed. Set it to default.\n"); EF_INFO("Warning: ENV CRC check failed. Set it to default.\n");
/* unlock the ENV cache */
ef_port_env_unlock();
result = ef_env_set_default(); result = ef_env_set_default();
break; return result;
} }
env.addr.start = GET_NEXT_FAILED; env.addr.start = GET_NEXT_FAILED;
/* search all ENV */ /* search all ENV */
@ -918,15 +953,21 @@ EfErrCode ef_load_env(void)
read_env(&env); read_env(&env);
/* recovery the prepare deleted ENV */ /* recovery the prepare deleted ENV */
if (env.crc_is_ok && env.status == ENV_PRE_DELETE) { if (env.crc_is_ok && env.status == ENV_PRE_DELETE) {
//TODO 增加新节点存储旧 ENV EF_DEBUG("Found a ENV (%.*s) which has changed value failed. Now will recovery it.\n", env.name_len, env.name);
//TODO 标记旧 ENV 为已删除 if ((env_addr = get_next_env_addr_by_size(&sector, env.len)) != GET_NEXT_FAILED) {
/* recovery the old ENV by flash copy */
copy_env(env.addr.start, env_addr, env.len);
/* delete the old ENV */
del_env(env.name, &env, true);
EF_DEBUG("Recovery the ENV to 0x%08X successful.\n", env_addr);
}
} }
} }
/* calculate next sector address */ /* calculate next sector address */
if (sector.combined == SECTOR_NOT_COMBINED) { if (sector.combined == SECTOR_NOT_COMBINED) {
addr += SECTOR_SIZE; sec_addr += SECTOR_SIZE;
} else { } else {
addr += sector.combined * SECTOR_SIZE; sec_addr += sector.combined * SECTOR_SIZE;
} }
} }

Loading…
Cancel
Save