Reworked compat flags a bit
Now with a bit more granularity for possibly-future-optional on-disk
data structures:
LFSR_RCOMPAT_NONSTANDARD 0x0001 ---- ---- ---- ---1 (reserved)
LFSR_RCOMPAT_MLEAF 0x0002 ---- ---- ---- --1-
LFSR_RCOMPAT_MSHRUB 0x0004 ---- ---- ---- -1-- (reserved)
LFSR_RCOMPAT_MTREE 0x0008 ---- ---- ---- 1---
LFSR_RCOMPAT_BSPROUT 0x0010 ---- ---- ---1 ----
LFSR_RCOMPAT_BLEAF 0x0020 ---- ---- --1- ----
LFSR_RCOMPAT_BSHRUB 0x0040 ---- ---- -1-- ----
LFSR_RCOMPAT_BTREE 0x0080 ---- ---- 1--- ----
LFSR_RCOMPAT_GRM 0x0100 ---- ---1 ---- ----
LFSR_WCOMPAT_NONSTANDARD 0x0001 ---- ---- ---- ---1 (reserved)
LFSR_OCOMPAT_NONSTANDARD 0x0001 ---- ---- ---- ---1 (reserved)
This adds a couple reserved flags:
- LFSR_*COMPAT_NONSTANDARD - This flag will never be set by a standard
version of littlefs. The idea is to allow implementations with
non-standard extensions a way to signal potential compatibility issues
without worrying about future compat flag conflicts.
This is limited to a single bit, but hey, it's not like it's possible
to predict all future extensions.
If a non-standard extension needs more granularity, reservations of
standard compat flags can always be requested, even if they don't end
up implemented in standard littlefs. (Though such reservations will
need a strong motivation, it's not like these flags are free).
- LFSR_RCOMPAT_MSHRUB - In theory littlefs supports a shrubbed mtree,
where the root is inlined into the mroot. But in practice this turned
out to be more complicated than it was worth. Still, a future
implementation may find an mshrub useful, so preserving a compat flag
for such a case makes sense.
That being said, I have no plans to add support for mshrubs even in
the dbg scripts.
I would like the expected feature-set for debug tools to be
well-defined, but also conservative. This gets a bit tricky with
theoretical features like the mshrubs, but until mshrubs are actually
implemented in littlefs, I would like to consider them non-standard.
The implication of this is that, while LFSR_RCOMPAT_MSHRUB is
currently "reserved", it may be repurposed for some other meaning in
the future.
These changes also rename *COMPATFLAGS -> *COMPAT, and reorder the tags
by decreasing importance. This ordering seems more valuable than the
original intention of making rcompat/wcompat a single bit flip.
Implementation-wise, it's interesting to note the internal-only
LFSR_*COMPAT_OVERFLOW flag. This gets set when out-of-range bits are set
on-disk, and allows us to detect unrepresentable compat flags without
too much extra complexity.
The extra encoding/decoding overhead does add a bit of cost though:
code stack
before: 33944 2880
after: 34124 (+0.5%) 2880 (+0.0%)
This commit is contained in:
+3
-3
@@ -14,9 +14,9 @@ TAG_NULL = 0x0000
|
||||
TAG_CONFIG = 0x0000
|
||||
TAG_MAGIC = 0x0003
|
||||
TAG_VERSION = 0x0004
|
||||
TAG_OCOMPATFLAGS = 0x0005
|
||||
TAG_RCOMPATFLAGS = 0x0006
|
||||
TAG_WCOMPATFLAGS = 0x0007
|
||||
TAG_RCOMPAT = 0x0005
|
||||
TAG_WCOMPAT = 0x0006
|
||||
TAG_OCOMPAT = 0x0007
|
||||
TAG_BLOCKSIZE = 0x0008
|
||||
TAG_BLOCKCOUNT = 0x0009
|
||||
TAG_NAMELIMIT = 0x000a
|
||||
|
||||
+6
-6
@@ -12,9 +12,9 @@ TAG_NULL = 0x0000
|
||||
TAG_CONFIG = 0x0000
|
||||
TAG_MAGIC = 0x0003
|
||||
TAG_VERSION = 0x0004
|
||||
TAG_OCOMPATFLAGS = 0x0005
|
||||
TAG_RCOMPATFLAGS = 0x0006
|
||||
TAG_WCOMPATFLAGS = 0x0007
|
||||
TAG_RCOMPAT = 0x0005
|
||||
TAG_WCOMPAT = 0x0006
|
||||
TAG_OCOMPAT = 0x0007
|
||||
TAG_BLOCKSIZE = 0x0008
|
||||
TAG_BLOCKCOUNT = 0x0009
|
||||
TAG_NAMELIMIT = 0x000a
|
||||
@@ -165,9 +165,9 @@ def tagrepr(tag, w, size, off=None):
|
||||
'shrub' if tag & TAG_SHRUB else '',
|
||||
'magic' if (tag & 0xfff) == TAG_MAGIC
|
||||
else 'version' if (tag & 0xfff) == TAG_VERSION
|
||||
else 'ocompatflags' if (tag & 0xfff) == TAG_OCOMPATFLAGS
|
||||
else 'rcompatflags' if (tag & 0xfff) == TAG_RCOMPATFLAGS
|
||||
else 'wcompatflags' if (tag & 0xfff) == TAG_WCOMPATFLAGS
|
||||
else 'rcompat' if (tag & 0xfff) == TAG_RCOMPAT
|
||||
else 'wcompat' if (tag & 0xfff) == TAG_WCOMPAT
|
||||
else 'ocompat' if (tag & 0xfff) == TAG_OCOMPAT
|
||||
else 'blocksize' if (tag & 0xfff) == TAG_BLOCKSIZE
|
||||
else 'blockcount' if (tag & 0xfff) == TAG_BLOCKCOUNT
|
||||
else 'sizelimit' if (tag & 0xfff) == TAG_SIZELIMIT
|
||||
|
||||
+24
-24
@@ -13,9 +13,9 @@ TAG_NULL = 0x0000
|
||||
TAG_CONFIG = 0x0000
|
||||
TAG_MAGIC = 0x0003
|
||||
TAG_VERSION = 0x0004
|
||||
TAG_OCOMPATFLAGS = 0x0005
|
||||
TAG_RCOMPATFLAGS = 0x0006
|
||||
TAG_WCOMPATFLAGS = 0x0007
|
||||
TAG_RCOMPAT = 0x0005
|
||||
TAG_WCOMPAT = 0x0006
|
||||
TAG_OCOMPAT = 0x0007
|
||||
TAG_BLOCKSIZE = 0x0008
|
||||
TAG_BLOCKCOUNT = 0x0009
|
||||
TAG_NAMELIMIT = 0x000a
|
||||
@@ -196,9 +196,9 @@ def tagrepr(tag, w, size, off=None):
|
||||
'shrub' if tag & TAG_SHRUB else '',
|
||||
'magic' if (tag & 0xfff) == TAG_MAGIC
|
||||
else 'version' if (tag & 0xfff) == TAG_VERSION
|
||||
else 'ocompatflags' if (tag & 0xfff) == TAG_OCOMPATFLAGS
|
||||
else 'rcompatflags' if (tag & 0xfff) == TAG_RCOMPATFLAGS
|
||||
else 'wcompatflags' if (tag & 0xfff) == TAG_WCOMPATFLAGS
|
||||
else 'rcompat' if (tag & 0xfff) == TAG_RCOMPAT
|
||||
else 'wcompat' if (tag & 0xfff) == TAG_WCOMPAT
|
||||
else 'ocompat' if (tag & 0xfff) == TAG_OCOMPAT
|
||||
else 'blocksize' if (tag & 0xfff) == TAG_BLOCKSIZE
|
||||
else 'blockcount' if (tag & 0xfff) == TAG_BLOCKCOUNT
|
||||
else 'sizelimit' if (tag & 0xfff) == TAG_SIZELIMIT
|
||||
@@ -1031,25 +1031,25 @@ class Config:
|
||||
return (None, None)
|
||||
|
||||
@ft.cached_property
|
||||
def ocompatflags(self):
|
||||
if TAG_OCOMPATFLAGS in self.config:
|
||||
_, data = self.config[TAG_OCOMPATFLAGS]
|
||||
def rcompat(self):
|
||||
if TAG_RCOMPAT in self.config:
|
||||
_, data = self.config[TAG_RCOMPAT]
|
||||
return data
|
||||
else:
|
||||
return None
|
||||
|
||||
@ft.cached_property
|
||||
def rcompatflags(self):
|
||||
if TAG_RCOMPATFLAGS in self.config:
|
||||
_, data = self.config[TAG_RCOMPATFLAGS]
|
||||
def wcompat(self):
|
||||
if TAG_WCOMPAT in self.config:
|
||||
_, data = self.config[TAG_WCOMPAT]
|
||||
return data
|
||||
else:
|
||||
return None
|
||||
|
||||
@ft.cached_property
|
||||
def wcompatflags(self):
|
||||
if TAG_WCOMPATFLAGS in self.config:
|
||||
_, data = self.config[TAG_WCOMPATFLAGS]
|
||||
def ocompat(self):
|
||||
if TAG_OCOMPAT in self.config:
|
||||
_, data = self.config[TAG_OCOMPAT]
|
||||
return data
|
||||
else:
|
||||
return None
|
||||
@@ -1098,15 +1098,15 @@ class Config:
|
||||
for b in map(chr, self.magic))
|
||||
elif tag == TAG_VERSION:
|
||||
return 'version v%d.%d' % self.version
|
||||
elif tag == TAG_OCOMPATFLAGS:
|
||||
return 'ocompatflags 0x%s' % ''.join(
|
||||
'%02x' % f for f in reversed(self.ocompatflags))
|
||||
elif tag == TAG_RCOMPATFLAGS:
|
||||
return 'rcompatflags 0x%s' % ''.join(
|
||||
'%02x' % f for f in reversed(self.rcompatflags))
|
||||
elif tag == TAG_WCOMPATFLAGS:
|
||||
return 'wcompatflags 0x%s' % ''.join(
|
||||
'%02x' % f for f in reversed(self.wcompatflags))
|
||||
elif tag == TAG_RCOMPAT:
|
||||
return 'rcompat 0x%s' % ''.join(
|
||||
'%x' % f for f in reversed(self.rcompat))
|
||||
elif tag == TAG_WCOMPAT:
|
||||
return 'wcompat 0x%s' % ''.join(
|
||||
'%x' % f for f in reversed(self.wcompat))
|
||||
elif tag == TAG_OCOMPAT:
|
||||
return 'ocompat 0x%s' % ''.join(
|
||||
'%x' % f for f in reversed(self.ocompat))
|
||||
elif tag == TAG_BLOCKSIZE:
|
||||
return 'blocksize %d' % self.block_size
|
||||
elif tag == TAG_BLOCKCOUNT:
|
||||
|
||||
+6
-6
@@ -12,9 +12,9 @@ TAG_NULL = 0x0000
|
||||
TAG_CONFIG = 0x0000
|
||||
TAG_MAGIC = 0x0003
|
||||
TAG_VERSION = 0x0004
|
||||
TAG_OCOMPATFLAGS = 0x0005
|
||||
TAG_RCOMPATFLAGS = 0x0006
|
||||
TAG_WCOMPATFLAGS = 0x0007
|
||||
TAG_RCOMPAT = 0x0005
|
||||
TAG_WCOMPAT = 0x0006
|
||||
TAG_OCOMPAT = 0x0007
|
||||
TAG_BLOCKSIZE = 0x0008
|
||||
TAG_BLOCKCOUNT = 0x0009
|
||||
TAG_NAMELIMIT = 0x000a
|
||||
@@ -180,9 +180,9 @@ def tagrepr(tag, w, size, off=None):
|
||||
'shrub' if tag & TAG_SHRUB else '',
|
||||
'magic' if (tag & 0xfff) == TAG_MAGIC
|
||||
else 'version' if (tag & 0xfff) == TAG_VERSION
|
||||
else 'ocompatflags' if (tag & 0xfff) == TAG_OCOMPATFLAGS
|
||||
else 'rcompatflags' if (tag & 0xfff) == TAG_RCOMPATFLAGS
|
||||
else 'wcompatflags' if (tag & 0xfff) == TAG_WCOMPATFLAGS
|
||||
else 'rcompat' if (tag & 0xfff) == TAG_RCOMPAT
|
||||
else 'wcompat' if (tag & 0xfff) == TAG_WCOMPAT
|
||||
else 'ocompat' if (tag & 0xfff) == TAG_OCOMPAT
|
||||
else 'blocksize' if (tag & 0xfff) == TAG_BLOCKSIZE
|
||||
else 'blockcount' if (tag & 0xfff) == TAG_BLOCKCOUNT
|
||||
else 'sizelimit' if (tag & 0xfff) == TAG_SIZELIMIT
|
||||
|
||||
+6
-6
@@ -21,9 +21,9 @@ TAG_NULL = 0x0000
|
||||
TAG_CONFIG = 0x0000
|
||||
TAG_MAGIC = 0x0003
|
||||
TAG_VERSION = 0x0004
|
||||
TAG_OCOMPATFLAGS = 0x0005
|
||||
TAG_RCOMPATFLAGS = 0x0006
|
||||
TAG_WCOMPATFLAGS = 0x0007
|
||||
TAG_RCOMPAT = 0x0005
|
||||
TAG_WCOMPAT = 0x0006
|
||||
TAG_OCOMPAT = 0x0007
|
||||
TAG_BLOCKSIZE = 0x0008
|
||||
TAG_BLOCKCOUNT = 0x0009
|
||||
TAG_NAMELIMIT = 0x000a
|
||||
@@ -167,9 +167,9 @@ def tagrepr(tag, w, size, off=None):
|
||||
'shrub' if tag & TAG_SHRUB else '',
|
||||
'magic' if (tag & 0xfff) == TAG_MAGIC
|
||||
else 'version' if (tag & 0xfff) == TAG_VERSION
|
||||
else 'ocompatflags' if (tag & 0xfff) == TAG_OCOMPATFLAGS
|
||||
else 'rcompatflags' if (tag & 0xfff) == TAG_RCOMPATFLAGS
|
||||
else 'wcompatflags' if (tag & 0xfff) == TAG_WCOMPATFLAGS
|
||||
else 'rcompat' if (tag & 0xfff) == TAG_RCOMPAT
|
||||
else 'wcompat' if (tag & 0xfff) == TAG_WCOMPAT
|
||||
else 'ocompat' if (tag & 0xfff) == TAG_OCOMPAT
|
||||
else 'blocksize' if (tag & 0xfff) == TAG_BLOCKSIZE
|
||||
else 'blockcount' if (tag & 0xfff) == TAG_BLOCKCOUNT
|
||||
else 'sizelimit' if (tag & 0xfff) == TAG_SIZELIMIT
|
||||
|
||||
Reference in New Issue
Block a user