修复IWDG超时未配置与dhara resume回滚:看门狗误复位与复位后写入全部丢失,台架全量自检PASS

This commit is contained in:
2026-10-02 20:48:30 +08:00
parent d1a2eaab07
commit 930215f81a
33 changed files with 1875 additions and 94 deletions
+31 -2
View File
@@ -553,7 +553,7 @@ int dhara_journal_resume(struct dhara_journal *j, dhara_error_t *err)
{
dhara_block_t first, last, last_any;
dhara_page_t last_group;
uint8_t first_epoch;
uint8_t first_epoch, last_epoch;
/* Find the first checkpoint-containing block */
if (find_checkblock(j, 0, &first, err) < 0) {
@@ -572,13 +572,42 @@ int dhara_journal_resume(struct dhara_journal *j, dhara_error_t *err)
* lifetime on the next resume. Measured 2026-09-20: this made a
* self-heal volume reformat vanish on every reset (infinite
* reformat loop, no data persistence).
*
* 2026-10-02 (local fix): the previous anchor picked the checkpoint
* at the HIGHEST block address. That is only the newest when the
* ring has not wrapped. The ring writes sequentially and bumps the
* epoch at each wrap, so once it HAS wrapped the newest checkpoints
* live at the LOWEST addresses and the highest-address ones are
* leftovers from the previous pass (one epoch older). Anchoring on
* those made every resume roll the journal back to the pre-wrap
* state: measured on the bench, head went 96 -> 130752 and tail
* 115143 -> 115068 on every reset, so NOTHING written after the
* wrap (log records, config saves, FTP uploads) ever survived a
* reset.
*
* Both cases are decided by comparing the two candidate epochs,
* which are always adjacent because the ring wraps at most once
* per pass:
* - equal -> no wrap between them; either is fine.
* - eFirst == eLast + 1 -> the ring wrapped; the low-address
* checkpoints are the newest.
* - otherwise -> the low-address checkpoints are stale
* leftovers; the high ones are newest.
*/
last_any = find_last_checkblock_any(j, first);
if (read_checkpage(j, last_any, err) < 0) {
reset_journal(j);
return -1;
}
j->epoch = hdr_get_epoch(j->page_buf);
last_epoch = hdr_get_epoch(j->page_buf);
if (first_epoch == last_epoch) {
j->epoch = first_epoch;
} else if ((uint8_t)(first_epoch - last_epoch) == 1u) {
j->epoch = first_epoch;
} else {
j->epoch = last_epoch;
}
if (first_epoch == j->epoch) {
/* Single-epoch ring: original code path, unchanged. */