FlashDB icon indicating copy to clipboard operation
FlashDB copied to clipboard

tsdb绕回写入时异常掉电,可能导致整个分区异常

Open ivan7wl opened this issue 3 years ago • 7 comments

测试发现在tsdb写入时如果有异常掉电,重新上电可能导致分区异常,log如下: Sector (0x00000000) header info is incorrect. All sector format finished.

review代码,疑似问题点如下: 如果使能绕回,在update_sec_status()函数中,有format_sector(db, new_sec_addr)调用,绕回时new_sec_addr为0。 如果在format_sector时候掉电,可能sector header还没写入,下次上电sector 0检查失败,就直接调用tsl_format_all(),把分区全擦除了。

ivan7wl avatar Mar 04 '21 08:03 ivan7wl

这么分析确实有可能的,此时分区要么非常干净都是 0xFF ,要么扇区头部信息写入一半

你有啥建议吗

armink avatar Mar 04 '21 14:03 armink

这种情况,如果sector 0信息丢失,是不是也是可以恢复到绕回之前的状态? 如果可以的话,那么改下上电检查的判断,如果sector 0出问题,再继续检查一下sector 1,sector 1正常的话是不是就不用全擦了?

ivan7wl avatar Mar 05 '21 01:03 ivan7wl

嗯,可否增加一个逻辑,如果只有当前这一个 sector 的 header 是坏的,那么就只把当前的删除格式化,其他还能继续用

armink avatar Mar 05 '21 12:03 armink

我初步研究了一下tsdb初始化流程,不知道如下修改方式是否可行:

  1. 检查每个sector的interator中,如果检查失败,就format_sector()格式化,按照empty处理,继续iterator sector
  2. 由于步骤1中的iterator中已经做了format,原先的check_sec_arg.check_failed检查然后tsl_format_all()的逻辑,就不再需要了

ivan7wl avatar Mar 06 '21 07:03 ivan7wl

可以的

  • arg->check_failed 从 bool 改为记录错误扇区的数量及地址
  • 迭代完后
    • 如果错误数量等于1并且没有找到正在使用的扇区,则格式化这个扇区并指定为正在使用扇区
    • 如果错误数量大于1,恐怕不能修复了,则只能全部格式化了

armink avatar Mar 06 '21 07:03 armink

我的意思是,迭代时把header检查失败的sector,做一次format,然后走empty的分支,就不会有check_failed的情况

static bool check_sec_hdr_cb(tsdb_sec_info_t sector, void *arg1, void *arg2)
{
    struct check_sec_hdr_cb_args *arg = arg1;
    fdb_tsdb_t db = arg->db;

    if (!sector->check_ok) {
        FDB_INFO("Sector (0x%08" PRIu32 ") header info is incorrect.\n", sector->addr);
        format_sector(db, sector->addr);
        sector->check_ok = true;
        sector->status = FDB_SECTOR_STORE_EMPTY;
        // is it necessary to call read_sector_info() ???
    }

    if (sector->status == FDB_SECTOR_STORE_USING) {
        if (db->cur_sec.addr == FDB_DATA_UNUSED) {
            memcpy(&db->cur_sec, sector, sizeof(struct tsdb_sec_info));
        } else {
            FDB_INFO("Warning: Sector status is wrong, there are multiple sectors in use.\n");
            (arg->check_failed) = true;
            return true;
        }
    } else if (sector->status == FDB_SECTOR_STORE_EMPTY) {
        (arg->empty_num) += 1;
        arg->empty_addr = sector->addr;
        if ((arg->empty_num) == 1 && db->cur_sec.addr == FDB_DATA_UNUSED) {
            memcpy(&db->cur_sec, sector, sizeof(struct tsdb_sec_info));
        }
    }

    return false;
}

ivan7wl avatar Mar 06 '21 07:03 ivan7wl

好的,你可以先验证一下

armink avatar Mar 06 '21 10:03 armink