Added phase bits to cksum tags
This carves out two more bits in cksum tags to store the "phase" of the
rbyd block (maybe the name is too fancy, this is just the lowest 2 bits
of the block address):
LFSR_TAG_CKSUM 0x300p v-11 ---- ---- -pqq
^ ^
| '-- phase bits
'---- perturb bit
The intention here is to catch mrootanchors that are "out-of-phase",
i.e. they've been shifted by a small number of blocks.
This can happen if we find the wrong mrootanchor (after, say, a magic
scan), and risks filesystem corruption:
formatted
.-----------------'-----------------.
mounted
.-----------------'-----------------.
.--------+--------+--------+--------+ ...
|(erased)| mroot |
| | anchor | ...
| | |
'--------+--------+--------+--------+ ...
Including the lower 2 bits of the block address in cksum tags avoids
this, for up to a 3 block shift (the maximum number of redund
mrootanchors).
---
Note that cksum tags really are the only place we could put these bits.
Anywhere else and they would interfere with the canonical cksum, which
would break error correction. By definition these need to be different
per block.
We include these phase bits in every cksum tag (because it's easier),
but these don't really say much about mdirs that are not the
mrootanchor. Non-anchor mdirs can have arbitrary block addresses,
therefore arbitrary phase bits.
You _might_ be able to do something interesting if you sort the rbyd
addresses and use the index as the phase bits, but that would add quite
a bit of code for questionable benefit...
You could argue this adds noise to our cksums, but:
1. 2 bits seems like a really small amount of noise
2. our cksums are just crc32cs
3. the phase bits humorously never change when you rewrite a block
---
As with any feature this adds code, but only a small amount. I think
it's worth the extra protection:
code stack ctx
before: 35792 2368 636
after: 35824 (+0.1%) 2368 (+0.0%) 636 (+0.0%)
Also added test_mount_incompat_out_of_phase to test this.
The dbg scripts _don't_ error (block mismatch seems likely when
debugging), but dbgrbyd.py at least adds phase mismatch notes in
-l/--log mode.
This commit is contained in:
@@ -1154,7 +1154,8 @@ enum lfsr_tag {
|
||||
|
||||
// checksum tags
|
||||
LFSR_TAG_CKSUM = 0x3000,
|
||||
LFSR_TAG_P = 0x0001,
|
||||
LFSR_TAG_PHASE = 0x0003,
|
||||
LFSR_TAG_PERTURB = 0x0004,
|
||||
LFSR_TAG_NOTE = 0x3100,
|
||||
LFSR_TAG_ECKSUM = 0x3200,
|
||||
LFSR_TAG_GCKSUMDELTA = 0x3300,
|
||||
@@ -1213,7 +1214,7 @@ static inline lfsr_tag_t lfsr_tag_subkey(lfsr_tag_t tag) {
|
||||
return tag & 0x00ff;
|
||||
}
|
||||
|
||||
static inline lfsr_tag_t lfsr_tag_redund(lfsr_tag_t tag) {
|
||||
static inline uint8_t lfsr_tag_redund(lfsr_tag_t tag) {
|
||||
return tag & 0x0003;
|
||||
}
|
||||
|
||||
@@ -1229,8 +1230,12 @@ static inline bool lfsr_tag_istrunk(lfsr_tag_t tag) {
|
||||
return lfsr_tag_mode(tag) != LFSR_TAG_CKSUM;
|
||||
}
|
||||
|
||||
static inline bool lfsr_tag_p(lfsr_tag_t tag) {
|
||||
return tag & LFSR_TAG_P;
|
||||
static inline uint8_t lfsr_tag_phase(lfsr_tag_t tag) {
|
||||
return tag & LFSR_TAG_PHASE;
|
||||
}
|
||||
|
||||
static inline bool lfsr_tag_perturb(lfsr_tag_t tag) {
|
||||
return tag & LFSR_TAG_PERTURB;
|
||||
}
|
||||
|
||||
static inline bool lfsr_tag_isinternal(lfsr_tag_t tag) {
|
||||
@@ -3013,11 +3018,17 @@ static int lfsr_rbyd_fetch_(lfs_t *lfs,
|
||||
|
||||
// is an end-of-commit cksum
|
||||
} else {
|
||||
// truncate checksum?
|
||||
// truncated checksum?
|
||||
if (size < sizeof(uint32_t)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// check phase
|
||||
if (lfsr_tag_phase(tag) != (block & 0x3)) {
|
||||
// uh oh, phase doesn't match, mounted incorrectly?
|
||||
break;
|
||||
}
|
||||
|
||||
// check checksum
|
||||
uint32_t cksum__ = 0;
|
||||
err = lfsr_bd_read(lfs, block, off_, -1,
|
||||
@@ -3037,7 +3048,7 @@ static int lfsr_rbyd_fetch_(lfs_t *lfs,
|
||||
|
||||
// save what we've found so far
|
||||
rbyd->eoff
|
||||
= ((lfs_size_t)lfsr_tag_p(tag)
|
||||
= ((lfs_size_t)lfsr_tag_perturb(tag)
|
||||
<< (8*sizeof(lfs_size_t)-1))
|
||||
| (off_ + size);
|
||||
rbyd->cksum = cksum;
|
||||
@@ -4488,7 +4499,10 @@ static int lfsr_rbyd_appendcksum_(lfs_t *lfs, lfsr_rbyd_t *rbyd,
|
||||
| ((uint8_t)v << 7);
|
||||
cksum_buf[1] = (uint8_t)(LFSR_TAG_CKSUM >> 0)
|
||||
// set the perturb bit so next commit is invalid
|
||||
| ((uint8_t)perturb << 0);
|
||||
| ((uint8_t)perturb << 2)
|
||||
// include the lower 2 bits of the block address to help
|
||||
// with resynchronization
|
||||
| (rbyd->blocks[0] & 0x3);
|
||||
cksum_buf[2] = 0;
|
||||
|
||||
lfs_size_t padding = off_ - (lfsr_rbyd_eoff(rbyd) + 2+1+4);
|
||||
|
||||
Reference in New Issue
Block a user