From 914733d0e0deddf40eb6e986e4334bd83b49fed0 Mon Sep 17 00:00:00 2001 From: armink Date: Wed, 6 Feb 2019 20:24:35 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E5=A2=9E=E5=8A=A0=E3=80=91GC=20?= =?UTF-8?q?=E5=A4=84=E7=90=86=E5=9F=BA=E6=9C=AC=E5=8A=9F=E8=83=BD=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E4=BB=A3=E7=A0=81=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: armink --- easyflash/src/ef_env_ng.c | 401 ++++++++++++++++++++++++-------------- 1 file changed, 253 insertions(+), 148 deletions(-) diff --git a/easyflash/src/ef_env_ng.c b/easyflash/src/ef_env_ng.c index d8f1ec3..39a1897 100644 --- a/easyflash/src/ef_env_ng.c +++ b/easyflash/src/ef_env_ng.c @@ -55,15 +55,20 @@ #define EF_STR_ENV_VALUE_MAX_SIZE 128 #endif -/* the sector remain max threshold before full status */ +/* the sector remain threshold before full status */ #ifndef EF_SEC_REMAIN_THRESHOLD #define EF_SEC_REMAIN_THRESHOLD (ENV_HDR_DATA_SIZE + EF_ENV_NAME_MAX) #endif +/* the total remain empty sector threshold before GC */ +#ifndef EF_GC_EMPTY_SEC_THRESHOLD +#define EF_GC_EMPTY_SEC_THRESHOLD 1 +#endif + /* the sector is not combined value */ #define SECTOR_NOT_COMBINED 0xFFFFFFFF /* the next address is get failed */ -#define GET_NEXT_FAILED 0xFFFFFFFF +#define GET_ADDR_FAILED 0xFFFFFFFF /* Return the most contiguous size aligned at specified width. RT_ALIGN(13, 4) * would return 16. @@ -109,6 +114,7 @@ enum sector_dirty_status { SECTOR_DIRTY_UNUSED, SECTOR_DIRTY_FALSE, SECTOR_DIRTY_TRUE, + SECTOR_DIRTY_GC, SECTOR_DIRTY_STATUS_NUM, }; typedef enum sector_dirty_status sector_dirty_status_t; @@ -119,7 +125,6 @@ enum env_status { ENV_WRITE, ENV_PRE_DELETE, ENV_DELETED, - ENV_GC, ENV_ERR_HDR, ENV_STATUS_NUM, }; @@ -137,6 +142,7 @@ struct sector_hdr_data { typedef struct sector_hdr_data *sector_hdr_data_t; struct sector_meta_data { + bool check_ok; /**< sector header check is OK */ struct { sector_store_status_t store; /**< sector store status @see sector_store_status_t */ sector_dirty_status_t dirty; /**< sector dirty status @see sector_dirty_status_t */ @@ -182,6 +188,8 @@ static size_t default_env_set_size = 0; static bool init_ok = false; /* the using status sector table */ static struct sector_meta_data using_sec_table[USING_SECTOR_TABLE_LEN]; +/* the GC is triggered */ +static bool gc_is_triggered = false; static size_t set_status(uint8_t status_table[], size_t status_num, size_t status_index) { @@ -266,37 +274,28 @@ static size_t read_status(uint32_t addr, uint8_t status_table[], size_t total_nu static uint32_t get_next_env_addr(sector_meta_data_t sector, env_meta_data_t pre_env) { uint8_t status_table[ENV_STATUS_TABLE_SIZE]; - uint32_t addr = GET_NEXT_FAILED; + uint32_t addr = GET_ADDR_FAILED; + + //TODO 可否直接共用 empty env addr if (sector->status.store == SECTOR_STORE_EMPTY) { - return GET_NEXT_FAILED; + return GET_ADDR_FAILED; } - if (pre_env->addr.start == GET_NEXT_FAILED) { + if (pre_env->addr.start == GET_ADDR_FAILED) { /* the first ENV address */ addr = sector->addr + SECTOR_HDR_DATA_SIZE; } else { if (pre_env->addr.start <= sector->addr + SECTOR_SIZE) { - if (pre_env->status == ENV_WRITE || pre_env->status == ENV_PRE_DELETE || pre_env->status == ENV_DELETED) { - /* next ENV address */ - addr = pre_env->addr.start + pre_env->len; - } else if (pre_env->status == ENV_PRE_WRITE || pre_env->status == ENV_ERR_HDR) { - if (pre_env->len == ~0UL) { - /* the ENV length has not write */ - addr = pre_env->addr.start + ENV_LEN_OFFSET; - } else if (pre_env->len <= SECTOR_SIZE - SECTOR_HDR_DATA_SIZE) { - addr = pre_env->addr.start + pre_env->len; - } else if (pre_env->len < ENV_AREA_SIZE) { - //TODO 扇区连续模式 - EF_ASSERT(0); - } - } else { - /* no ENV */ - return GET_NEXT_FAILED; + /* next ENV address */ + addr = pre_env->addr.start + pre_env->len; + if (addr > sector->addr + SECTOR_SIZE) { + //TODO 扇区连续模式 + EF_ASSERT(0); } } else { /* no ENV */ - return GET_NEXT_FAILED; + return GET_ADDR_FAILED; } } /* check ENV status, it's ENV_UNUSED when not using */ @@ -304,7 +303,7 @@ static uint32_t get_next_env_addr(sector_meta_data_t sector, env_meta_data_t pre return addr; } else { /* no ENV */ - return GET_NEXT_FAILED; + return GET_ADDR_FAILED; } } @@ -372,8 +371,10 @@ static EfErrCode read_sector_meta_data(uint32_t addr, sector_meta_data_t sector, sector->magic = sec_hdr.magic; /* check magic word */ if (sector->magic != SECTOR_MAGIC_WORD) { + sector->check_ok = false; return EF_ENV_INIT_FAILED; } + sector->check_ok = true; /* get other sector meta data */ sector->combined = sec_hdr.combined; sector->status.store = get_status(sec_hdr.status_table.store, SECTOR_STORE_STATUS_NUM); @@ -387,24 +388,18 @@ static EfErrCode read_sector_meta_data(uint32_t addr, sector_meta_data_t sector, } else if (sector->status.store == SECTOR_STORE_USING) { struct env_meta_data env_meta; sector->remain = SECTOR_SIZE - SECTOR_HDR_DATA_SIZE; - env_meta.addr.start = GET_NEXT_FAILED; - while ((env_meta.addr.start = get_next_env_addr(sector, &env_meta)) != GET_NEXT_FAILED) { + env_meta.addr.start = GET_ADDR_FAILED; + while ((env_meta.addr.start = get_next_env_addr(sector, &env_meta)) != GET_ADDR_FAILED) { read_env(&env_meta); - if (env_meta.crc_is_ok) { - sector->empty_env += env_meta.len; - sector->remain -= env_meta.len; - //TODO 大块数据占用连续扇区情形的处理 - } else { + if (!env_meta.crc_is_ok) { //TODO 完善 CRC 校验出错后的处理,比如标记扇区已经损坏 if (env_meta.status == ENV_PRE_WRITE || env_meta.status == ENV_ERR_HDR) { - //TODO 简化与其他地方的重复代码 + /* ENV length was not write */ if (env_meta.len == ~0UL) { - /* the ENV length has not write */ - sector->empty_env += ENV_LEN_OFFSET; - } else if (env_meta.len <= SECTOR_SIZE - SECTOR_HDR_DATA_SIZE) { - sector->empty_env += env_meta.len; - } else if (env_meta.len < ENV_AREA_SIZE) { - //TODO 扇区连续模式 + /* the ENV length was not write */ + env_meta.len = ENV_LEN_OFFSET; + } else if (env_meta.len > SECTOR_SIZE - SECTOR_HDR_DATA_SIZE && env_meta.len < ENV_AREA_SIZE) { + //TODO 扇区连续模式,或者写入长度没有写入完整 EF_ASSERT(0); } } else { @@ -414,6 +409,8 @@ static EfErrCode read_sector_meta_data(uint32_t addr, sector_meta_data_t sector, break; } } + sector->empty_env += env_meta.len; + sector->remain -= env_meta.len; } } } @@ -425,7 +422,7 @@ static uint32_t get_next_sector_addr(sector_meta_data_t pre_sec) { uint32_t next_addr; - if (pre_sec->addr == GET_NEXT_FAILED) { + if (pre_sec->addr == GET_ADDR_FAILED) { return env_start_addr; } else { /* check ENV sector combined */ @@ -439,7 +436,7 @@ static uint32_t get_next_sector_addr(sector_meta_data_t pre_sec) return next_addr; } else { /* no sector */ - return GET_NEXT_FAILED; + return GET_ADDR_FAILED; } } } @@ -452,18 +449,21 @@ static void env_iterator(env_meta_data_t env, void *arg1, void *arg2, //TODO 支持通过 using_sec_table 遍历 - sector.addr = GET_NEXT_FAILED; + sector.addr = GET_ADDR_FAILED; /* search all sectors */ - while ((sec_addr = get_next_sector_addr(§or)) != GET_NEXT_FAILED) { + while ((sec_addr = get_next_sector_addr(§or)) != GET_ADDR_FAILED) { //TODO 检查所有扇区的剩余空间,是否有合适的扇区,优先 using_sec_table if (read_sector_meta_data(sec_addr, §or, false) != EF_NO_ERR) { continue; } + if (callback == NULL) { + continue; + } /* sector has ENV */ if (sector.status.store == SECTOR_STORE_USING || sector.status.store == SECTOR_STORE_FULL) { - env->addr.start = GET_NEXT_FAILED; + env->addr.start = GET_ADDR_FAILED; /* search all ENV */ - while ((env->addr.start = get_next_env_addr(§or, env)) != GET_NEXT_FAILED) { + while ((env->addr.start = get_next_env_addr(§or, env)) != GET_ADDR_FAILED) { read_env(env); /* iterator is interrupted when callback return true */ if (callback(env, arg1, arg2)) { @@ -559,23 +559,160 @@ static EfErrCode write_env_hdr(uint32_t addr, env_hdr_data_t env_hdr) { return result; } -static uint32_t get_next_env_addr_by_size(sector_meta_data_t sector, size_t env_size) +static EfErrCode format_sector(uint32_t addr, uint32_t combined_value) +{ + EfErrCode result = EF_NO_ERR; + struct sector_hdr_data sec_hdr; + + EF_ASSERT(addr % SECTOR_SIZE == 0); + + result = ef_port_erase(addr, SECTOR_SIZE); + if (result == EF_NO_ERR) { + /* initialize the header data */ + memset(&sec_hdr, 0xFF, sizeof(struct sector_hdr_data)); + set_status(sec_hdr.status_table.store, SECTOR_STORE_STATUS_NUM, SECTOR_STORE_EMPTY); + set_status(sec_hdr.status_table.dirty, SECTOR_DIRTY_STATUS_NUM, SECTOR_DIRTY_FALSE); + sec_hdr.magic = SECTOR_MAGIC_WORD; + sec_hdr.combined = combined_value; + sec_hdr.reserved = 0xFFFFFFFF; + /* save the header */ + ef_port_write(addr, (uint32_t *)&sec_hdr, sizeof(struct sector_hdr_data)); + } + + return result; +} + +static EfErrCode copy_env(uint32_t to, uint32_t from, 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]; + env_len -= ENV_LEN_OFFSET; + 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; +} + +static void sector_iterator(sector_meta_data_t sector, void *arg1, void *arg2, + bool (*callback)(sector_meta_data_t sector, void *arg1, void *arg2), bool traversal_env) { uint32_t sec_addr; + /* search all sectors */ - sector->addr = GET_NEXT_FAILED; - while ((sec_addr = get_next_sector_addr(sector)) != GET_NEXT_FAILED) { + sector->addr = GET_ADDR_FAILED; + while ((sec_addr = get_next_sector_addr(sector)) != GET_ADDR_FAILED) { //TODO 检查所有扇区的剩余空间,是否有合适的扇区,优先 using_sec_table - if (read_sector_meta_data(sec_addr, sector, true) != EF_NO_ERR) { - continue; + read_sector_meta_data(sec_addr, sector, traversal_env); + /* iterator is interrupted when callback return true */ + if (callback && callback(sector, arg1, arg2)) { + return; } - /* sector has space */ - if (sector->remain > env_size) { - return sector->empty_env; + } +} + +static bool alloc_env_cb(sector_meta_data_t sector, void *arg1, void *arg2) +{ + size_t *env_size = arg1; + uint32_t *empty_env = arg2; + + /* sector has space */ + if (sector->check_ok && sector->remain > *env_size) { + *empty_env = sector->empty_env; + return true; + } + + return false; +} + +static uint32_t alloc_env(sector_meta_data_t sector, size_t env_size) +{ + uint32_t empty_env = GET_ADDR_FAILED; + + sector_iterator(sector, &env_size, &empty_env, alloc_env_cb, true); + + return empty_env; +} + +static bool gc_check_cb(sector_meta_data_t sector, void *arg1, void *arg2) +{ + size_t *empty_sec = arg1; + + if (sector->check_ok && sector->status.store == SECTOR_STORE_EMPTY) { + *empty_sec = *empty_sec + 1; + } + + return false; + +} + +static bool do_gc(sector_meta_data_t sector, void *arg1, void *arg2) +{ + struct env_meta_data env; + + if (sector->check_ok && sector->status.store == SECTOR_STORE_FULL + && (sector->status.dirty == SECTOR_DIRTY_TRUE || sector->status.dirty == SECTOR_DIRTY_GC)) { +#if (ENV_STATUS_TABLE_SIZE >= DIRTY_STATUS_TABLE_SIZE) + uint8_t status_table[ENV_STATUS_TABLE_SIZE]; +#else + uint8_t status_table[DIRTY_STATUS_TABLE_SIZE]; +#endif + //TODO 重复写入安全性验证 + /* change the sector status to GC */ + write_status(sector->addr, status_table, SECTOR_DIRTY_STATUS_NUM, SECTOR_DIRTY_GC); + /* search all ENV */ + env.addr.start = GET_ADDR_FAILED; + while ((env.addr.start = get_next_env_addr(sector, &env)) != GET_ADDR_FAILED) { + read_env(&env); + if (env.crc_is_ok && (env.status == ENV_WRITE || env.status == ENV_PRE_DELETE)) { + uint32_t env_addr; + struct sector_meta_data new_sector; + //TODO 异常掉电测试 + //TODO 修改新扇区状态 + write_status(env.addr.start, status_table, ENV_STATUS_NUM, ENV_PRE_DELETE); + /* alloc new space for move the old ENV */ + if ((env_addr = alloc_env(&new_sector, env.len)) != GET_ADDR_FAILED) { + /* copy the old ENV to new space */ + copy_env(env_addr, env.addr.start, env.len); + } + write_status(env.addr.start, status_table, ENV_STATUS_NUM, ENV_DELETED); + } } + format_sector(sector->addr, SECTOR_NOT_COMBINED); + EF_DEBUG("Collect a sector @0x%08X\n", sector->addr); } - return GET_NEXT_FAILED; + return false; +} + +static void gc_collect(void) +{ + struct sector_meta_data sector; + size_t empty_sec = 0; + + /* GC check the empty sector number */ + sector_iterator(§or, &empty_sec, NULL, gc_check_cb, false); + + /* do GC collect */ + if (empty_sec <= EF_GC_EMPTY_SEC_THRESHOLD) { + EF_DEBUG("The remain empty sector is %d, GC threshold is %d.\n", empty_sec, EF_GC_EMPTY_SEC_THRESHOLD); + sector_iterator(§or, NULL, NULL, do_gc, false); + } } static EfErrCode create_env_blob(const char *key, const void *value, size_t len) @@ -584,6 +721,7 @@ static EfErrCode create_env_blob(const char *key, const void *value, size_t len) struct env_hdr_data env_hdr; static struct sector_meta_data sector; uint32_t env_addr; + bool is_full = false; if (strlen(key) > EF_ENV_NAME_MAX) { EF_INFO("Error: The ENV name length is more than %d\n", EF_ENV_NAME_MAX); @@ -600,7 +738,7 @@ static EfErrCode create_env_blob(const char *key, const void *value, size_t len) return EF_ENV_FULL; } - if ((env_addr = get_next_env_addr_by_size(§or, env_hdr.len)) != GET_NEXT_FAILED) { + if ((env_addr = alloc_env(§or, env_hdr.len)) != GET_ADDR_FAILED) { size_t align_remain; uint32_t sec_addr = EF_ALIGN_DOWN(env_addr, SECTOR_SIZE); /* change the sector status to SECTOR_STORE_USING */ @@ -615,6 +753,7 @@ static EfErrCode create_env_blob(const char *key, const void *value, size_t len) if (sector.remain - env_hdr.len < EF_SEC_REMAIN_THRESHOLD) { /* change the sector status to full */ result = write_status(sec_addr, status_table, SECTOR_STORE_STATUS_NUM, SECTOR_STORE_FULL); + is_full = true; } } } @@ -648,6 +787,14 @@ static EfErrCode create_env_blob(const char *key, const void *value, size_t len) if (result == EF_NO_ERR) { result = write_status(env_addr, env_hdr.status_table, ENV_STATUS_NUM, ENV_WRITE); } + /* trigger GC collect when current sector is full */ + if (result == EF_NO_ERR && is_full) { + uint8_t status_table[DIRTY_STATUS_TABLE_SIZE]; + /* change the sector status to GC */ + write_status(sector.addr, status_table, SECTOR_DIRTY_STATUS_NUM, SECTOR_DIRTY_GC); + EF_DEBUG("Trigger a GC collect.\n"); + gc_is_triggered = true; + } //TODO 更新 using_sec_table } @@ -758,6 +905,11 @@ EfErrCode ef_set_env(const char *key, const char *value) if (env_is_found && result == EF_NO_ERR) { result = del_env(key, &env, true); } + /* process the GC after set ENV */ + if (result == EF_NO_ERR && gc_is_triggered) { + gc_collect(); + gc_is_triggered = false; + } } /* unlock the ENV cache */ @@ -775,29 +927,6 @@ EfErrCode ef_save_env(void) return EF_NO_ERR; } -static EfErrCode format_sector(uint32_t addr, uint32_t combined_value) -{ - EfErrCode result = EF_NO_ERR; - struct sector_hdr_data sec_hdr; - - EF_ASSERT(addr % SECTOR_SIZE == 0); - - result = ef_port_erase(addr, SECTOR_SIZE); - if (result == EF_NO_ERR) { - /* initialize the header data */ - memset(&sec_hdr, 0xFF, sizeof(struct sector_hdr_data)); - set_status(sec_hdr.status_table.store, SECTOR_STORE_STATUS_NUM, SECTOR_STORE_EMPTY); - set_status(sec_hdr.status_table.dirty, SECTOR_DIRTY_STATUS_NUM, SECTOR_DIRTY_FALSE); - sec_hdr.magic = SECTOR_MAGIC_WORD; - sec_hdr.combined = combined_value; - sec_hdr.reserved = 0xFFFFFFFF; - /* save the header */ - ef_port_write(addr, (uint32_t *)&sec_hdr, sizeof(struct sector_hdr_data)); - } - - return result; -} - /** * ENV set default. * @@ -907,6 +1036,7 @@ void ef_print_env(void) env_iterator(&env, &using_size, NULL, print_env_cb); + ef_print("\nmode: next generation\n"); ef_print("size: %lu/%lu bytes.\n", using_size + SECTOR_NUM * SECTOR_HDR_DATA_SIZE, ENV_AREA_SIZE); /* unlock the ENV cache */ @@ -935,31 +1065,52 @@ static EfErrCode env_auto_update(void) } #endif /* EF_ENV_AUTO_UPDATE */ -static EfErrCode copy_env(uint32_t to, uint32_t from, size_t env_len) +static bool check_sec_hdr_cb(sector_meta_data_t sector, void *arg1, void *arg2) { - EfErrCode result = EF_NO_ERR; - uint8_t status_table[ENV_STATUS_TABLE_SIZE]; + if (!sector->check_ok) { + EF_INFO("Warning: Sector header check failed. Set it to default.\n"); + ef_port_env_unlock(); + ef_env_set_default(); + ef_port_env_lock(); + return true; + } else if(sector->status.dirty == SECTOR_DIRTY_GC) { + /* resume the GC operate */ + gc_collect(); + } - result = write_status(to, status_table, ENV_STATUS_NUM, ENV_PRE_WRITE); - if (result == EF_NO_ERR) { - uint8_t buf[32]; - env_len -= ENV_LEN_OFFSET; - 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; + return false; +} + +static bool check_and_recovery_env_cb(env_meta_data_t env, void *arg1, void *arg2) +{ + uint32_t env_addr; + + /* recovery the prepare deleted ENV */ + if (env->crc_is_ok && env->status == ENV_PRE_DELETE) { + struct sector_meta_data sector; + EF_INFO("Found a ENV (%.*s) which has changed value failed. Now will recovery it.\n", env->name_len, env->name); + if ((env_addr = alloc_env(§or, env->len)) != GET_ADDR_FAILED) { + struct env_meta_data env_bak; + char name[EF_ENV_NAME_MAX + 1] = { 0 }; + strncpy(name, env->name, env->name_len); + /* check the ENV is already create success */ + if (!find_env(name, &env_bak)) { + /* recovery the old ENV by flash copy */ + copy_env(env_addr, env->addr.start, env->len); } + /* delete the old ENV */ + del_env(name, env, true); + EF_INFO("Recovery the ENV to 0x%08X successful.\n", env_addr); } - result = write_status(to, status_table, ENV_STATUS_NUM, ENV_WRITE); + } else if (env->status == ENV_PRE_WRITE) { + uint8_t status_table[ENV_STATUS_TABLE_SIZE]; + /* the ENV has not write finish, change the status to error */ + //TODO 绘制异常处理的状态装换图 + write_status(env->addr.start, status_table, ENV_STATUS_NUM, ENV_ERR_HDR); + return true; } - return result; + return false; } /** @@ -970,64 +1121,18 @@ static EfErrCode copy_env(uint32_t to, uint32_t from, size_t env_len) EfErrCode ef_load_env(void) { EfErrCode result = EF_NO_ERR; - uint32_t sec_addr, env_addr; - struct sector_meta_data sector; struct env_meta_data env; + struct sector_meta_data sector; /* lock the ENV cache */ ef_port_env_lock(); - //TODO 检查是否存在未完成的环境变量操作,存在则执行掉电恢复 - //TODO 检查是否存在未完成的垃圾回收工作,存在则继续整理 //TODO 装载环境变量元数据,using_sec_table - /* read all sectors */ - for (sec_addr = env_start_addr; sec_addr < env_start_addr + ENV_AREA_SIZE; ) { - /* check sector header */ - result = read_sector_meta_data(sec_addr, §or, false); - if (result!= EF_NO_ERR) { - 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(); - return result; - } - env.addr.start = GET_NEXT_FAILED; - /* search all ENV */ - while ((env.addr.start = get_next_env_addr(§or, &env)) != GET_NEXT_FAILED) { - read_env(&env); - /* recovery the prepare deleted ENV */ - if (env.crc_is_ok && env.status == ENV_PRE_DELETE) { - uint32_t sec_start_bak = sector.addr; - EF_INFO("Found a ENV (%.*s) which has changed value failed. Now will recovery it.\n", env.name_len, env.name); - if ((env_addr = get_next_env_addr_by_size(§or, env.len)) != GET_NEXT_FAILED) { - struct env_meta_data env_bak; - char name[EF_ENV_NAME_MAX + 1] = { 0 }; - strncpy(name, env.name, env.name_len); - /* check the ENV is already create success */ - if (!find_env(name, &env_bak)) { - /* recovery the old ENV by flash copy */ - copy_env(env_addr, env.addr.start, env.len); - } - /* delete the old ENV */ - del_env(name, &env, true); - EF_INFO("Recovery the ENV to 0x%08X successful.\n", env_addr); - } - sector.addr = sec_start_bak; - } else if (env.status == ENV_PRE_WRITE) { - uint8_t status_table[ENV_STATUS_TABLE_SIZE]; - /* the ENV has not write finish, change the status to error */ - //TODO 绘制异常处理的状态装换图 - write_status(env.addr.start, status_table, ENV_STATUS_NUM, ENV_ERR_HDR); - break; - } - } - /* calculate next sector address */ - if (sector.combined == SECTOR_NOT_COMBINED) { - sec_addr += SECTOR_SIZE; - } else { - sec_addr += sector.combined * SECTOR_SIZE; - } - } + //TODO 检查是否存在未完成的垃圾回收工作,存在则垃圾回收 + /* check all sector header */ + sector_iterator(§or, NULL, NULL, check_sec_hdr_cb, false); + /* check all ENV for recovery */ + env_iterator(&env, NULL, NULL, check_and_recovery_env_cb); /* unlock the ENV cache */ ef_port_env_unlock();