E-31修复:dhara resume失败按错误分类(仅真空白判新卷),mount失败自检上报+主循环有界重试
This commit is contained in:
+53
-16
@@ -218,12 +218,20 @@ void dhara_journal_init(struct dhara_journal *j,
|
||||
/* Find the first checkpoint-containing block. If a block contains any
|
||||
* checkpoints at all, then it must contain one in the first checkpoint
|
||||
* location -- otherwise, we would have considered the block eraseable.
|
||||
*
|
||||
* Error contract (E-31 fix, 2026-09-21): DHARA_E_TOO_BAD is reported
|
||||
* only when the scan completed without any I/O error (genuinely blank
|
||||
* chip -- safe for the caller to start fresh). Any read failure in the
|
||||
* scan is reported instead as the first such error, so callers can
|
||||
* distinguish "no checkpoints exist" from "the scan was interrupted by
|
||||
* I/O trouble" -- treating the latter as blank would wipe a live volume.
|
||||
*/
|
||||
static int find_checkblock(struct dhara_journal *j,
|
||||
dhara_block_t blk, dhara_block_t *where,
|
||||
dhara_error_t *err)
|
||||
{
|
||||
int i;
|
||||
dhara_error_t io_err = DHARA_E_NONE;
|
||||
|
||||
for (i = 0; (blk < j->nand->num_blocks) &&
|
||||
(i < DHARA_MAX_RETRIES); i++) {
|
||||
@@ -231,19 +239,27 @@ static int find_checkblock(struct dhara_journal *j,
|
||||
(blk << j->nand->log2_ppb) |
|
||||
((1 << j->log2_ppc) - 1);
|
||||
|
||||
if (!(dhara_nand_is_bad(j->nand, blk) ||
|
||||
dhara_nand_read(j->nand, p,
|
||||
0, 1 << j->nand->log2_page_size,
|
||||
j->page_buf, err)) &&
|
||||
hdr_has_magic(j->page_buf)) {
|
||||
*where = blk;
|
||||
return 0;
|
||||
if (dhara_nand_is_bad(j->nand, blk)) {
|
||||
/* Bad block: no read performed, no I/O error */
|
||||
} else {
|
||||
dhara_error_t read_err = DHARA_E_NONE;
|
||||
|
||||
if (dhara_nand_read(j->nand, p,
|
||||
0, 1 << j->nand->log2_page_size,
|
||||
j->page_buf, &read_err) < 0) {
|
||||
if (io_err == DHARA_E_NONE)
|
||||
io_err = read_err;
|
||||
} else if (hdr_has_magic(j->page_buf)) {
|
||||
*where = blk;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
blk++;
|
||||
}
|
||||
|
||||
dhara_set_error(err, DHARA_E_TOO_BAD);
|
||||
dhara_set_error(err,
|
||||
(io_err != DHARA_E_NONE) ? io_err : DHARA_E_TOO_BAD);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -315,7 +331,11 @@ static dhara_block_t find_last_checkblock_any(struct dhara_journal *j,
|
||||
}
|
||||
|
||||
/* Re-read the first-group checkpoint header of the given block into
|
||||
* j->page_buf. Returns 0 on success. */
|
||||
* j->page_buf. Returns 0 on success. A failed read reports the I/O
|
||||
* error; a successful read that no longer carries the checkpoint magic
|
||||
* is an inconsistency (the block was verified to hold a checkpoint
|
||||
* during the scan) and reports DHARA_E_CORRUPT_MAP -- never
|
||||
* DHARA_E_TOO_BAD, which callers treat as a blank chip (E-31 fix). */
|
||||
static int read_checkpage(struct dhara_journal *j, dhara_block_t blk,
|
||||
dhara_error_t *err)
|
||||
{
|
||||
@@ -323,10 +343,14 @@ static int read_checkpage(struct dhara_journal *j, dhara_block_t blk,
|
||||
((1 << j->log2_ppc) - 1);
|
||||
|
||||
if (dhara_nand_read(j->nand, p, 0, 1 << j->nand->log2_page_size,
|
||||
j->page_buf, err) < 0 ||
|
||||
!hdr_has_magic(j->page_buf))
|
||||
j->page_buf, err) < 0)
|
||||
return -1;
|
||||
|
||||
if (!hdr_has_magic(j->page_buf)) {
|
||||
dhara_set_error(err, DHARA_E_CORRUPT_MAP);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -437,16 +461,20 @@ static int find_root(struct dhara_journal *j, dhara_page_t start,
|
||||
{
|
||||
const dhara_block_t blk = start >> j->nand->log2_ppb;
|
||||
int i = (start & ((1 << j->nand->log2_ppb) - 1)) >> j->log2_ppc;
|
||||
dhara_error_t io_err = DHARA_E_NONE;
|
||||
|
||||
while (i >= 0) {
|
||||
const dhara_page_t p = (blk << j->nand->log2_ppb) +
|
||||
((i + 1) << j->log2_ppc) - 1;
|
||||
dhara_error_t read_err = DHARA_E_NONE;
|
||||
|
||||
if (!dhara_nand_read(j->nand, p,
|
||||
if (dhara_nand_read(j->nand, p,
|
||||
0, 1 << j->nand->log2_page_size,
|
||||
j->page_buf, err) &&
|
||||
(hdr_has_magic(j->page_buf)) &&
|
||||
(hdr_get_epoch(j->page_buf) == j->epoch)) {
|
||||
j->page_buf, &read_err) < 0) {
|
||||
if (io_err == DHARA_E_NONE)
|
||||
io_err = read_err;
|
||||
} else if ((hdr_has_magic(j->page_buf)) &&
|
||||
(hdr_get_epoch(j->page_buf) == j->epoch)) {
|
||||
j->root = p - 1;
|
||||
return 0;
|
||||
}
|
||||
@@ -454,7 +482,16 @@ static int find_root(struct dhara_journal *j, dhara_page_t start,
|
||||
i--;
|
||||
}
|
||||
|
||||
dhara_set_error(err, DHARA_E_TOO_BAD);
|
||||
/* The checkpoint ring is already established by the time this
|
||||
* runs (find_checkblock + epoch verification succeeded), so
|
||||
* "no matching checkpoint" here means the stored checkpoint is
|
||||
* inconsistent (read flakiness or real corruption): report an
|
||||
* I/O error if one occurred, else DHARA_E_CORRUPT_MAP -- never
|
||||
* DHARA_E_TOO_BAD, which callers treat as a blank chip
|
||||
* (E-31 fix, 2026-09-21).
|
||||
*/
|
||||
dhara_set_error(err,
|
||||
(io_err != DHARA_E_NONE) ? io_err : DHARA_E_CORRUPT_MAP);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user