armink / EasyFlash

Lightweight IoT device information storage solution: KV/IAP/LOG. | 轻量级物联网设备信息存储方案:参数存储、在线升级及日志存储 ,全新一代版本请移步至 https://github.com/armink/FlashDB
MIT License
2.01k stars 765 forks source link

配合ulog使用读取的时候 ef_log 在临界条件下存在低概率卡死的可能 #147

Closed i-jaffer closed 1 year ago

i-jaffer commented 1 year ago
  1. ef_log_read()函数针对 index < cur_using_size的情况判断不应使用断言 EF_ASSERT(index < cur_using_size);,断言程序直接就卡死了,不合理,可以返回错误
  2. rtt下配合ulog使用读取的时候 ef_log 在临界条件下存在低概率卡死的可能,情况如下:

    • 假定总共有ABCD四页的空间存储log,每页4096字节
    • 假定ABC已存满日志,D即将存满,取极限情况已写入4094字节,此时调用了ulog的日志读取函数 read_flash_log() 从4096*3+4044 处读取50字节数据(等同于调用read_recent_flash_log读取最后50字节数据)
      
      /**
    • Read and output log to console.
    • @param index index for saved log.
    • Minimum index is 0.
    • Maximum index is log used flash total size - 1.
    • @param size / static void read_flash_log(size_t index, size_t size) { / 64 bytes buffer */ uint32_t buf[16] = { 0 }; size_t log_total_size = ef_log_get_used_size(); //此时D还未写满,处于即将写满的状态,每页4096字节,已写入4094字节 size_t buf_size = sizeof(buf); size_t read_size = 0;

    / word alignment for index and size / index = RT_ALIGN_DOWN(index, 4); size = RT_ALIGN_DOWN(size, 4); if (index + size > log_total_size) { rt_kprintf("The output position and size is out of bound. The max size is %d.\n", log_total_size); return; } / 假定在此附件由于线程超时或其他中断触发,最终导致线程被抢占,其他线程往flash里面记录了日志,导致D扇区写满, 将A扇区擦除,这会导致log_total_size减小,之后在后续程序中调用 ef_log_read 时会触发 ef_log_read 函数内的断言错误 EF_ASSERT(index < cur_using_size); 导致程序卡死 / while (1) { if (read_size + buf_size < size) { ef_log_read(index + read_size, buf, buf_size); rt_kprintf("%.s", buf_size, buf); read_size += buf_size; } else { ef_log_read(index + read_size, buf, size - read_size); rt_kprintf("%.s", size - read_size, buf); / output newline sign / rt_kprintf(ULOG_NEWLINE_SIGN); break; } } }