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:
Christopher Haster
2025-04-29 17:31:12 -05:00
parent 97f8eeb9e9
commit de7564e448
9 changed files with 141 additions and 56 deletions
+21 -7
View File
@@ -1154,7 +1154,8 @@ enum lfsr_tag {
// checksum tags // checksum tags
LFSR_TAG_CKSUM = 0x3000, LFSR_TAG_CKSUM = 0x3000,
LFSR_TAG_P = 0x0001, LFSR_TAG_PHASE = 0x0003,
LFSR_TAG_PERTURB = 0x0004,
LFSR_TAG_NOTE = 0x3100, LFSR_TAG_NOTE = 0x3100,
LFSR_TAG_ECKSUM = 0x3200, LFSR_TAG_ECKSUM = 0x3200,
LFSR_TAG_GCKSUMDELTA = 0x3300, LFSR_TAG_GCKSUMDELTA = 0x3300,
@@ -1213,7 +1214,7 @@ static inline lfsr_tag_t lfsr_tag_subkey(lfsr_tag_t tag) {
return tag & 0x00ff; 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; 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; return lfsr_tag_mode(tag) != LFSR_TAG_CKSUM;
} }
static inline bool lfsr_tag_p(lfsr_tag_t tag) { static inline uint8_t lfsr_tag_phase(lfsr_tag_t tag) {
return tag & LFSR_TAG_P; 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) { 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 // is an end-of-commit cksum
} else { } else {
// truncate checksum? // truncated checksum?
if (size < sizeof(uint32_t)) { if (size < sizeof(uint32_t)) {
break; break;
} }
// check phase
if (lfsr_tag_phase(tag) != (block & 0x3)) {
// uh oh, phase doesn't match, mounted incorrectly?
break;
}
// check checksum // check checksum
uint32_t cksum__ = 0; uint32_t cksum__ = 0;
err = lfsr_bd_read(lfs, block, off_, -1, 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 // save what we've found so far
rbyd->eoff rbyd->eoff
= ((lfs_size_t)lfsr_tag_p(tag) = ((lfs_size_t)lfsr_tag_perturb(tag)
<< (8*sizeof(lfs_size_t)-1)) << (8*sizeof(lfs_size_t)-1))
| (off_ + size); | (off_ + size);
rbyd->cksum = cksum; rbyd->cksum = cksum;
@@ -4488,7 +4499,10 @@ static int lfsr_rbyd_appendcksum_(lfs_t *lfs, lfsr_rbyd_t *rbyd,
| ((uint8_t)v << 7); | ((uint8_t)v << 7);
cksum_buf[1] = (uint8_t)(LFSR_TAG_CKSUM >> 0) cksum_buf[1] = (uint8_t)(LFSR_TAG_CKSUM >> 0)
// set the perturb bit so next commit is invalid // 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; cksum_buf[2] = 0;
lfs_size_t padding = off_ - (lfsr_rbyd_eoff(rbyd) + 2+1+4); lfs_size_t padding = off_ - (lfsr_rbyd_eoff(rbyd) + 2+1+4);
+9 -7
View File
@@ -67,8 +67,9 @@ TAG_B = 0x0000
TAG_R = 0x2000 TAG_R = 0x2000
TAG_LE = 0x0000 TAG_LE = 0x0000
TAG_GT = 0x1000 TAG_GT = 0x1000
TAG_CKSUM = 0x3000 ## 0x300p v-11 ---- ---- ---p TAG_CKSUM = 0x3000 ## 0x300p v-11 ---- ---- -pqq
TAG_P = 0x0001 TAG_PHASE = 0x0003
TAG_PERTURB = 0x0004
TAG_NOTE = 0x3100 ## 0x3100 v-11 ---1 ---- ---- TAG_NOTE = 0x3100 ## 0x3100 v-11 ---1 ---- ----
TAG_ECKSUM = 0x3200 ## 0x3200 v-11 --1- ---- ---- TAG_ECKSUM = 0x3200 ## 0x3200 v-11 --1- ---- ----
TAG_GCKSUMDELTA = 0x3300 ## 0x3300 v-11 --11 ---- ---- TAG_GCKSUMDELTA = 0x3300 ## 0x3300 v-11 --11 ---- ----
@@ -346,7 +347,7 @@ def tagrepr(tag, weight=None, size=None, *,
return '%s%sattr 0x%02x%s%s' % ( return '%s%sattr 0x%02x%s%s' % (
'shrub' if tag & TAG_SHRUB else '', 'shrub' if tag & TAG_SHRUB else '',
's' if tag & 0x100 else 'u', 's' if tag & 0x100 else 'u',
((tag & 0x100) >> 1) ^ (tag & 0xff), ((tag & 0x100) >> 1) + (tag & 0xff),
' w%d' % weight if weight else '', ' w%d' % weight if weight else '',
' %s' % size if size is not None else '') ' %s' % size if size is not None else '')
# alt pointers # alt pointers
@@ -362,9 +363,10 @@ def tagrepr(tag, weight=None, size=None, *,
else '') else '')
# checksum tags # checksum tags
elif (tag & 0x7f00) == TAG_CKSUM: elif (tag & 0x7f00) == TAG_CKSUM:
return 'cksum%s%s%s%s' % ( return 'cksum%s%s%s%s%s' % (
'p' if not tag & 0xfe and tag & TAG_P else '', 'q%d' % (tag & 0x3),
' 0x%02x' % (tag & 0xff) if tag & 0xfe else '', 'p' if tag & TAG_PERTURB else '',
' 0x%02x' % (tag & 0xff) if tag & 0xf8 else '',
' w%d' % weight if weight else '', ' w%d' % weight if weight else '',
' %s' % size if size is not None else '') ' %s' % size if size is not None else '')
# note tags # note tags
@@ -684,7 +686,7 @@ class Rbyd:
gcksumdelta = gcksumdelta_ gcksumdelta = gcksumdelta_
gcksumdelta_ = None gcksumdelta_ = None
# update perturb bit # update perturb bit
perturb = tag & TAG_P perturb = bool(tag & TAG_PERTURB)
# revert to data cksum and perturb # revert to data cksum and perturb
cksum__ = cksum_ ^ (0xfca42daf if perturb else 0) cksum__ = cksum_ ^ (0xfca42daf if perturb else 0)
+9 -7
View File
@@ -65,8 +65,9 @@ TAG_B = 0x0000
TAG_R = 0x2000 TAG_R = 0x2000
TAG_LE = 0x0000 TAG_LE = 0x0000
TAG_GT = 0x1000 TAG_GT = 0x1000
TAG_CKSUM = 0x3000 ## 0x300p v-11 ---- ---- ---p TAG_CKSUM = 0x3000 ## 0x300p v-11 ---- ---- -pqq
TAG_P = 0x0001 TAG_PHASE = 0x0003
TAG_PERTURB = 0x0004
TAG_NOTE = 0x3100 ## 0x3100 v-11 ---1 ---- ---- TAG_NOTE = 0x3100 ## 0x3100 v-11 ---1 ---- ----
TAG_ECKSUM = 0x3200 ## 0x3200 v-11 --1- ---- ---- TAG_ECKSUM = 0x3200 ## 0x3200 v-11 --1- ---- ----
TAG_GCKSUMDELTA = 0x3300 ## 0x3300 v-11 --11 ---- ---- TAG_GCKSUMDELTA = 0x3300 ## 0x3300 v-11 --11 ---- ----
@@ -376,7 +377,7 @@ def tagrepr(tag, weight=None, size=None, *,
return '%s%sattr 0x%02x%s%s' % ( return '%s%sattr 0x%02x%s%s' % (
'shrub' if tag & TAG_SHRUB else '', 'shrub' if tag & TAG_SHRUB else '',
's' if tag & 0x100 else 'u', 's' if tag & 0x100 else 'u',
((tag & 0x100) >> 1) ^ (tag & 0xff), ((tag & 0x100) >> 1) + (tag & 0xff),
' w%d' % weight if weight else '', ' w%d' % weight if weight else '',
' %s' % size if size is not None else '') ' %s' % size if size is not None else '')
# alt pointers # alt pointers
@@ -392,9 +393,10 @@ def tagrepr(tag, weight=None, size=None, *,
else '') else '')
# checksum tags # checksum tags
elif (tag & 0x7f00) == TAG_CKSUM: elif (tag & 0x7f00) == TAG_CKSUM:
return 'cksum%s%s%s%s' % ( return 'cksum%s%s%s%s%s' % (
'p' if not tag & 0xfe and tag & TAG_P else '', 'q%d' % (tag & 0x3),
' 0x%02x' % (tag & 0xff) if tag & 0xfe else '', 'p' if tag & TAG_PERTURB else '',
' 0x%02x' % (tag & 0xff) if tag & 0xf8 else '',
' w%d' % weight if weight else '', ' w%d' % weight if weight else '',
' %s' % size if size is not None else '') ' %s' % size if size is not None else '')
# note tags # note tags
@@ -714,7 +716,7 @@ class Rbyd:
gcksumdelta = gcksumdelta_ gcksumdelta = gcksumdelta_
gcksumdelta_ = None gcksumdelta_ = None
# update perturb bit # update perturb bit
perturb = tag & TAG_P perturb = bool(tag & TAG_PERTURB)
# revert to data cksum and perturb # revert to data cksum and perturb
cksum__ = cksum_ ^ (0xfca42daf if perturb else 0) cksum__ = cksum_ ^ (0xfca42daf if perturb else 0)
+9 -7
View File
@@ -56,8 +56,9 @@ TAG_B = 0x0000
TAG_R = 0x2000 TAG_R = 0x2000
TAG_LE = 0x0000 TAG_LE = 0x0000
TAG_GT = 0x1000 TAG_GT = 0x1000
TAG_CKSUM = 0x3000 ## 0x300p v-11 ---- ---- ---p TAG_CKSUM = 0x3000 ## 0x300p v-11 ---- ---- -pqq
TAG_P = 0x0001 TAG_PHASE = 0x0003
TAG_PERTURB = 0x0004
TAG_NOTE = 0x3100 ## 0x3100 v-11 ---1 ---- ---- TAG_NOTE = 0x3100 ## 0x3100 v-11 ---1 ---- ----
TAG_ECKSUM = 0x3200 ## 0x3200 v-11 --1- ---- ---- TAG_ECKSUM = 0x3200 ## 0x3200 v-11 --1- ---- ----
TAG_GCKSUMDELTA = 0x3300 ## 0x3300 v-11 --11 ---- ---- TAG_GCKSUMDELTA = 0x3300 ## 0x3300 v-11 --11 ---- ----
@@ -254,7 +255,7 @@ def tagrepr(tag, weight=None, size=None, *,
return '%s%sattr 0x%02x%s%s' % ( return '%s%sattr 0x%02x%s%s' % (
'shrub' if tag & TAG_SHRUB else '', 'shrub' if tag & TAG_SHRUB else '',
's' if tag & 0x100 else 'u', 's' if tag & 0x100 else 'u',
((tag & 0x100) >> 1) ^ (tag & 0xff), ((tag & 0x100) >> 1) + (tag & 0xff),
' w%d' % weight if weight else '', ' w%d' % weight if weight else '',
' %s' % size if size is not None else '') ' %s' % size if size is not None else '')
# alt pointers # alt pointers
@@ -270,9 +271,10 @@ def tagrepr(tag, weight=None, size=None, *,
else '') else '')
# checksum tags # checksum tags
elif (tag & 0x7f00) == TAG_CKSUM: elif (tag & 0x7f00) == TAG_CKSUM:
return 'cksum%s%s%s%s' % ( return 'cksum%s%s%s%s%s' % (
'p' if not tag & 0xfe and tag & TAG_P else '', 'q%d' % (tag & 0x3),
' 0x%02x' % (tag & 0xff) if tag & 0xfe else '', 'p' if tag & TAG_PERTURB else '',
' 0x%02x' % (tag & 0xff) if tag & 0xf8 else '',
' w%d' % weight if weight else '', ' w%d' % weight if weight else '',
' %s' % size if size is not None else '') ' %s' % size if size is not None else '')
# note tags # note tags
@@ -592,7 +594,7 @@ class Rbyd:
gcksumdelta = gcksumdelta_ gcksumdelta = gcksumdelta_
gcksumdelta_ = None gcksumdelta_ = None
# update perturb bit # update perturb bit
perturb = tag & TAG_P perturb = bool(tag & TAG_PERTURB)
# revert to data cksum and perturb # revert to data cksum and perturb
cksum__ = cksum_ ^ (0xfca42daf if perturb else 0) cksum__ = cksum_ ^ (0xfca42daf if perturb else 0)
+9 -7
View File
@@ -57,8 +57,9 @@ TAG_B = 0x0000
TAG_R = 0x2000 TAG_R = 0x2000
TAG_LE = 0x0000 TAG_LE = 0x0000
TAG_GT = 0x1000 TAG_GT = 0x1000
TAG_CKSUM = 0x3000 ## 0x300p v-11 ---- ---- ---p TAG_CKSUM = 0x3000 ## 0x300p v-11 ---- ---- -pqq
TAG_P = 0x0001 TAG_PHASE = 0x0003
TAG_PERTURB = 0x0004
TAG_NOTE = 0x3100 ## 0x3100 v-11 ---1 ---- ---- TAG_NOTE = 0x3100 ## 0x3100 v-11 ---1 ---- ----
TAG_ECKSUM = 0x3200 ## 0x3200 v-11 --1- ---- ---- TAG_ECKSUM = 0x3200 ## 0x3200 v-11 --1- ---- ----
TAG_GCKSUMDELTA = 0x3300 ## 0x3300 v-11 --11 ---- ---- TAG_GCKSUMDELTA = 0x3300 ## 0x3300 v-11 --11 ---- ----
@@ -303,7 +304,7 @@ def tagrepr(tag, weight=None, size=None, *,
return '%s%sattr 0x%02x%s%s' % ( return '%s%sattr 0x%02x%s%s' % (
'shrub' if tag & TAG_SHRUB else '', 'shrub' if tag & TAG_SHRUB else '',
's' if tag & 0x100 else 'u', 's' if tag & 0x100 else 'u',
((tag & 0x100) >> 1) ^ (tag & 0xff), ((tag & 0x100) >> 1) + (tag & 0xff),
' w%d' % weight if weight else '', ' w%d' % weight if weight else '',
' %s' % size if size is not None else '') ' %s' % size if size is not None else '')
# alt pointers # alt pointers
@@ -319,9 +320,10 @@ def tagrepr(tag, weight=None, size=None, *,
else '') else '')
# checksum tags # checksum tags
elif (tag & 0x7f00) == TAG_CKSUM: elif (tag & 0x7f00) == TAG_CKSUM:
return 'cksum%s%s%s%s' % ( return 'cksum%s%s%s%s%s' % (
'p' if not tag & 0xfe and tag & TAG_P else '', 'q%d' % (tag & 0x3),
' 0x%02x' % (tag & 0xff) if tag & 0xfe else '', 'p' if tag & TAG_PERTURB else '',
' 0x%02x' % (tag & 0xff) if tag & 0xf8 else '',
' w%d' % weight if weight else '', ' w%d' % weight if weight else '',
' %s' % size if size is not None else '') ' %s' % size if size is not None else '')
# note tags # note tags
@@ -641,7 +643,7 @@ class Rbyd:
gcksumdelta = gcksumdelta_ gcksumdelta = gcksumdelta_
gcksumdelta_ = None gcksumdelta_ = None
# update perturb bit # update perturb bit
perturb = tag & TAG_P perturb = bool(tag & TAG_PERTURB)
# revert to data cksum and perturb # revert to data cksum and perturb
cksum__ = cksum_ ^ (0xfca42daf if perturb else 0) cksum__ = cksum_ ^ (0xfca42daf if perturb else 0)
+9 -7
View File
@@ -56,8 +56,9 @@ TAG_B = 0x0000
TAG_R = 0x2000 TAG_R = 0x2000
TAG_LE = 0x0000 TAG_LE = 0x0000
TAG_GT = 0x1000 TAG_GT = 0x1000
TAG_CKSUM = 0x3000 ## 0x300p v-11 ---- ---- ---p TAG_CKSUM = 0x3000 ## 0x300p v-11 ---- ---- -pqq
TAG_P = 0x0001 TAG_PHASE = 0x0003
TAG_PERTURB = 0x0004
TAG_NOTE = 0x3100 ## 0x3100 v-11 ---1 ---- ---- TAG_NOTE = 0x3100 ## 0x3100 v-11 ---1 ---- ----
TAG_ECKSUM = 0x3200 ## 0x3200 v-11 --1- ---- ---- TAG_ECKSUM = 0x3200 ## 0x3200 v-11 --1- ---- ----
TAG_GCKSUMDELTA = 0x3300 ## 0x3300 v-11 --11 ---- ---- TAG_GCKSUMDELTA = 0x3300 ## 0x3300 v-11 --11 ---- ----
@@ -269,7 +270,7 @@ def tagrepr(tag, weight=None, size=None, *,
return '%s%sattr 0x%02x%s%s' % ( return '%s%sattr 0x%02x%s%s' % (
'shrub' if tag & TAG_SHRUB else '', 'shrub' if tag & TAG_SHRUB else '',
's' if tag & 0x100 else 'u', 's' if tag & 0x100 else 'u',
((tag & 0x100) >> 1) ^ (tag & 0xff), ((tag & 0x100) >> 1) + (tag & 0xff),
' w%d' % weight if weight else '', ' w%d' % weight if weight else '',
' %s' % size if size is not None else '') ' %s' % size if size is not None else '')
# alt pointers # alt pointers
@@ -285,9 +286,10 @@ def tagrepr(tag, weight=None, size=None, *,
else '') else '')
# checksum tags # checksum tags
elif (tag & 0x7f00) == TAG_CKSUM: elif (tag & 0x7f00) == TAG_CKSUM:
return 'cksum%s%s%s%s' % ( return 'cksum%s%s%s%s%s' % (
'p' if not tag & 0xfe and tag & TAG_P else '', 'q%d' % (tag & 0x3),
' 0x%02x' % (tag & 0xff) if tag & 0xfe else '', 'p' if tag & TAG_PERTURB else '',
' 0x%02x' % (tag & 0xff) if tag & 0xf8 else '',
' w%d' % weight if weight else '', ' w%d' % weight if weight else '',
' %s' % size if size is not None else '') ' %s' % size if size is not None else '')
# note tags # note tags
@@ -607,7 +609,7 @@ class Rbyd:
gcksumdelta = gcksumdelta_ gcksumdelta = gcksumdelta_
gcksumdelta_ = None gcksumdelta_ = None
# update perturb bit # update perturb bit
perturb = tag & TAG_P perturb = bool(tag & TAG_PERTURB)
# revert to data cksum and perturb # revert to data cksum and perturb
cksum__ = cksum_ ^ (0xfca42daf if perturb else 0) cksum__ = cksum_ ^ (0xfca42daf if perturb else 0)
+15 -8
View File
@@ -66,8 +66,9 @@ TAG_B = 0x0000
TAG_R = 0x2000 TAG_R = 0x2000
TAG_LE = 0x0000 TAG_LE = 0x0000
TAG_GT = 0x1000 TAG_GT = 0x1000
TAG_CKSUM = 0x3000 ## 0x300p v-11 ---- ---- ---p TAG_CKSUM = 0x3000 ## 0x300p v-11 ---- ---- -pqq
TAG_P = 0x0001 TAG_PHASE = 0x0003
TAG_PERTURB = 0x0004
TAG_NOTE = 0x3100 ## 0x3100 v-11 ---1 ---- ---- TAG_NOTE = 0x3100 ## 0x3100 v-11 ---1 ---- ----
TAG_ECKSUM = 0x3200 ## 0x3200 v-11 --1- ---- ---- TAG_ECKSUM = 0x3200 ## 0x3200 v-11 --1- ---- ----
TAG_GCKSUMDELTA = 0x3300 ## 0x3300 v-11 --11 ---- ---- TAG_GCKSUMDELTA = 0x3300 ## 0x3300 v-11 --11 ---- ----
@@ -257,7 +258,7 @@ def tagrepr(tag, weight=None, size=None, *,
return '%s%sattr 0x%02x%s%s' % ( return '%s%sattr 0x%02x%s%s' % (
'shrub' if tag & TAG_SHRUB else '', 'shrub' if tag & TAG_SHRUB else '',
's' if tag & 0x100 else 'u', 's' if tag & 0x100 else 'u',
((tag & 0x100) >> 1) ^ (tag & 0xff), ((tag & 0x100) >> 1) + (tag & 0xff),
' w%d' % weight if weight else '', ' w%d' % weight if weight else '',
' %s' % size if size is not None else '') ' %s' % size if size is not None else '')
# alt pointers # alt pointers
@@ -273,9 +274,10 @@ def tagrepr(tag, weight=None, size=None, *,
else '') else '')
# checksum tags # checksum tags
elif (tag & 0x7f00) == TAG_CKSUM: elif (tag & 0x7f00) == TAG_CKSUM:
return 'cksum%s%s%s%s' % ( return 'cksum%s%s%s%s%s' % (
'p' if not tag & 0xfe and tag & TAG_P else '', 'q%d' % (tag & 0x3),
' 0x%02x' % (tag & 0xff) if tag & 0xfe else '', 'p' if tag & TAG_PERTURB else '',
' 0x%02x' % (tag & 0xff) if tag & 0xf8 else '',
' w%d' % weight if weight else '', ' w%d' % weight if weight else '',
' %s' % size if size is not None else '') ' %s' % size if size is not None else '')
# note tags # note tags
@@ -575,7 +577,7 @@ class Rbyd:
gcksumdelta = gcksumdelta_ gcksumdelta = gcksumdelta_
gcksumdelta_ = None gcksumdelta_ = None
# update perturb bit # update perturb bit
perturb = tag & TAG_P perturb = bool(tag & TAG_PERTURB)
# revert to data cksum and perturb # revert to data cksum and perturb
cksum__ = cksum_ ^ (0xfca42daf if perturb else 0) cksum__ = cksum_ ^ (0xfca42daf if perturb else 0)
@@ -1548,6 +1550,7 @@ def dbg_log(rbyd, *,
# read next tag # read next tag
j = j_ j = j_
v, tag, w, size, d = fromtag(data, j_) v, tag, w, size, d = fromtag(data, j_)
# note if parity doesn't match
if v != parity(cksum_): if v != parity(cksum_):
notes.append('v!=%x' % parity(cksum_)) notes.append('v!=%x' % parity(cksum_))
cksum_ ^= 0x00000080 if v else 0 cksum_ ^= 0x00000080 if v else 0
@@ -1560,12 +1563,16 @@ def dbg_log(rbyd, *,
cksum_ = crc32c(data[j_:j_+size], cksum_) cksum_ = crc32c(data[j_:j_+size], cksum_)
# found a cksum? # found a cksum?
else: else:
# note if phase doesn't match
if (tag & 0x3) != (rbyd.block & 0x3):
notes.append('q!=%x' % (rbyd.block & 0x3))
# check cksum # check cksum
cksum__ = fromle32(data, j_) cksum__ = fromle32(data, j_)
# note if cksum doesn't match
if cksum_ != cksum__: if cksum_ != cksum__:
notes.append('cksum!=%08x' % cksum__) notes.append('cksum!=%08x' % cksum__)
# update perturb bit # update perturb bit
perturb = tag & TAG_P perturb = bool(tag & TAG_PERTURB)
# revert to data cksum and perturb # revert to data cksum and perturb
cksum_ = cksum ^ (0xfca42daf if perturb else 0) cksum_ = cksum ^ (0xfca42daf if perturb else 0)
j_ += size j_ += size
+8 -6
View File
@@ -49,8 +49,9 @@ TAG_B = 0x0000
TAG_R = 0x2000 TAG_R = 0x2000
TAG_LE = 0x0000 TAG_LE = 0x0000
TAG_GT = 0x1000 TAG_GT = 0x1000
TAG_CKSUM = 0x3000 ## 0x300p v-11 ---- ---- ---p TAG_CKSUM = 0x3000 ## 0x300p v-11 ---- ---- -pqq
TAG_P = 0x0001 TAG_PHASE = 0x0003
TAG_PERTURB = 0x0004
TAG_NOTE = 0x3100 ## 0x3100 v-11 ---1 ---- ---- TAG_NOTE = 0x3100 ## 0x3100 v-11 ---1 ---- ----
TAG_ECKSUM = 0x3200 ## 0x3200 v-11 --1- ---- ---- TAG_ECKSUM = 0x3200 ## 0x3200 v-11 --1- ---- ----
TAG_GCKSUMDELTA = 0x3300 ## 0x3300 v-11 --11 ---- ---- TAG_GCKSUMDELTA = 0x3300 ## 0x3300 v-11 --11 ---- ----
@@ -161,7 +162,7 @@ def tagrepr(tag, weight=None, size=None, *,
return '%s%sattr 0x%02x%s%s' % ( return '%s%sattr 0x%02x%s%s' % (
'shrub' if tag & TAG_SHRUB else '', 'shrub' if tag & TAG_SHRUB else '',
's' if tag & 0x100 else 'u', 's' if tag & 0x100 else 'u',
((tag & 0x100) >> 1) ^ (tag & 0xff), ((tag & 0x100) >> 1) + (tag & 0xff),
' w%d' % weight if weight else '', ' w%d' % weight if weight else '',
' %s' % size if size is not None else '') ' %s' % size if size is not None else '')
# alt pointers # alt pointers
@@ -177,9 +178,10 @@ def tagrepr(tag, weight=None, size=None, *,
else '') else '')
# checksum tags # checksum tags
elif (tag & 0x7f00) == TAG_CKSUM: elif (tag & 0x7f00) == TAG_CKSUM:
return 'cksum%s%s%s%s' % ( return 'cksum%s%s%s%s%s' % (
'p' if not tag & 0xfe and tag & TAG_P else '', 'q%d' % (tag & 0x3),
' 0x%02x' % (tag & 0xff) if tag & 0xfe else '', 'p' if tag & TAG_PERTURB else '',
' 0x%02x' % (tag & 0xff) if tag & 0xf8 else '',
' w%d' % weight if weight else '', ' w%d' % weight if weight else '',
' %s' % size if size is not None else '') ' %s' % size if size is not None else '')
# note tags # note tags
+52
View File
@@ -1963,3 +1963,55 @@ code = '''
lfsr_unmount(&lfs) => 0; lfsr_unmount(&lfs) => 0;
''' '''
# Ok, here's an interesting one, test that we fail if we're
# "out-of-phase", i.e. the mrootanchor has 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. To prevent this, we include 2
# phase bits in cksum tags to detect up to a 3 block shift (the maximum
# number of redund mrootanchors)
#
[cases.test_mount_incompat_out_of_phase]
defines.PHASE = [1, 2, 3, 4]
in = 'lfs.c'
code = '''
// create a superblock
lfs_t lfs;
lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0;
// with some files
lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_file_t file;
lfsr_file_open(&lfs, &file, "r2d2",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
char wbuf[256];
strcpy(wbuf, "beep boop");
lfsr_file_write(&lfs, &file, wbuf, strlen(wbuf)) => strlen(wbuf);
lfsr_file_close(&lfs, &file) => 0;
lfsr_file_open(&lfs, &file, "c3po",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
strcpy(wbuf, "we seem to be made to suffer");
lfsr_file_write(&lfs, &file, wbuf, strlen(wbuf)) => strlen(wbuf);
lfsr_file_close(&lfs, &file) => 0;
// shift the filesystem out-of-phase
uint8_t shift_buf[BLOCK_SIZE];
for (lfs_size_t i = 0; i < 4; i++) {
CFG->read(CFG, 4-1-i, 0, shift_buf, BLOCK_SIZE) => 0;
CFG->erase(CFG, 4-1-i + PHASE) => 0;
CFG->prog(CFG, 4-1-i + PHASE, 0, shift_buf, BLOCK_SIZE) => 0;
memset(shift_buf, 0, BLOCK_SIZE);
strcpy((char*)shift_buf,
"these aren't the files you're looking for ;)");
CFG->erase(CFG, 4-1-i) => 0;
CFG->prog(CFG, 4-1-i, 0, shift_buf, BLOCK_SIZE) => 0;
}
// mount should now fail
lfsr_mount(&lfs, LFS_M_RDWR, CFG) => LFS_ERR_CORRUPT;
lfsr_mount(&lfs, LFS_M_RDONLY, CFG) => LFS_ERR_CORRUPT;
'''