Replaced separate BLOCKSIZE/BLOCKCOUNT attrs with single GEOMETRY attr
This saves a bit of rbyd overhead, since these almost always come
together.
Perhaps more interesting, it carves out space for storing mroot-anchor
redundancy information. This uses the lowest two bits of the GEOMETRY
tag to indicate how many redundant blocks belong to the mroot-anchor:
LFSR_TAG_GEOMETRY 0x0008 v--- ---- ---- 1-rr
This solves a bit of a hole in our redundancy encoding. The plan is for
this info to be stored in the lowest two bits of every pointer, but the
mroot-anchor doesn't really have a pointer.
Though this is just future plans. Right now the redundancy information
is unused. Current implementations should use the GEOMETRY tag 0x0009,
which you may notice implied redundancy level-1. This matches our
current 2-block per mdir default.
Geometry attr encoding:
.---+---+---+---. tag (0x0008+r): 1 be16 2 bytes
|x0008+r| 0 |siz| weight (0): 1 leb128 1 byte
+---+---+---+---+ size: 1 leb128 1 byte
| block_size | block_size: 1 leb128 <=4 bytes
+---+- -+- -+- -+- -.
| block_count | block_count: 1 leb128 <=5 bytes
'---+- -+- -+- -+- -' total: <=13 bytes
Code changes:
code stack
before: 34092 2880
after: 34040 (-0.2%) 2880 (+0.0%)
This commit is contained in:
@@ -721,10 +721,9 @@ enum lfsr_tag {
|
||||
LFSR_TAG_RCOMPAT = 0x0005,
|
||||
LFSR_TAG_WCOMPAT = 0x0006,
|
||||
LFSR_TAG_OCOMPAT = 0x0007,
|
||||
LFSR_TAG_BLOCKSIZE = 0x0008,
|
||||
LFSR_TAG_BLOCKCOUNT = 0x0009,
|
||||
LFSR_TAG_NAMELIMIT = 0x000a,
|
||||
LFSR_TAG_SIZELIMIT = 0x000b,
|
||||
LFSR_TAG_GEOMETRY = 0x0009,
|
||||
LFSR_TAG_NAMELIMIT = 0x000c,
|
||||
LFSR_TAG_SIZELIMIT = 0x000d,
|
||||
|
||||
// global-state tags
|
||||
LFSR_TAG_GDELTA = 0x0100,
|
||||
@@ -7884,6 +7883,59 @@ static int lfsr_data_readwcompat(lfs_t *lfs, lfsr_data_t *data,
|
||||
}
|
||||
|
||||
|
||||
// disk geometry
|
||||
//
|
||||
// note these are stored minus 1 to avoid overflow issues
|
||||
typedef struct lfsr_geometry {
|
||||
lfs_off_t block_size;
|
||||
lfs_off_t block_count;
|
||||
} lfsr_geometry_t;
|
||||
|
||||
// geometry encoding
|
||||
// .---+- -+- -+- -.
|
||||
// | block_size | blocksize: <=4 bytes
|
||||
// +---+- -+- -+- -+- -.
|
||||
// | block_count | blockcount: <=5 bytes
|
||||
// '---+- -+- -+- -+- -' total: <=9 bytes
|
||||
#define LFSR_GEOMETRY_DSIZE (4+5)
|
||||
|
||||
#define LFSR_DATA_FROMGEOMETRY(_geometry) \
|
||||
lfsr_data_fromgeometry(_geometry, (uint8_t[LFSR_GEOMETRY_DSIZE]){0})
|
||||
|
||||
static lfsr_data_t lfsr_data_fromgeometry(const lfsr_geometry_t *geometry,
|
||||
uint8_t buffer[static LFSR_GEOMETRY_DSIZE]) {
|
||||
lfs_ssize_t d = 0;
|
||||
lfs_ssize_t d_ = lfs_toleb128(geometry->block_size-1, &buffer[d], 4);
|
||||
LFS_ASSERT(d_ >= 0);
|
||||
d += d_;
|
||||
|
||||
d_ = lfs_toleb128(geometry->block_count-1, &buffer[d], 5);
|
||||
LFS_ASSERT(d_ >= 0);
|
||||
d += d_;
|
||||
|
||||
return LFSR_DATA_BUF(buffer, d);
|
||||
}
|
||||
|
||||
static int lfsr_data_readgeometry(lfs_t *lfs, lfsr_data_t *data,
|
||||
lfsr_geometry_t *geometry) {
|
||||
int err = lfsr_data_readlleb128(lfs, data,
|
||||
(uint32_t*)&geometry->block_size);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = lfsr_data_readleb128(lfs, data,
|
||||
(uint32_t*)&geometry->block_count);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
geometry->block_size += 1;
|
||||
geometry->block_count += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/// Filesystem init functions ///
|
||||
|
||||
static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg);
|
||||
@@ -7993,52 +8045,33 @@ static int lfsr_mountmroot(lfs_t *lfs, const lfsr_mdir_t *mroot) {
|
||||
// we don't bother to check for any ocompatflags, we would just
|
||||
// ignore these anyways
|
||||
|
||||
// check block size
|
||||
err = lfsr_mdir_lookup(lfs, mroot, LFSR_TAG_BLOCKSIZE,
|
||||
// check the on-disk geometry
|
||||
err = lfsr_mdir_lookup(lfs, mroot, LFSR_TAG_GEOMETRY,
|
||||
&data);
|
||||
if (err && err != LFS_ERR_NOENT) {
|
||||
if (err) {
|
||||
if (err == LFS_ERR_NOENT) {
|
||||
LFS_ERROR("No geometry found");
|
||||
return LFS_ERR_INVAL;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
uint32_t block_size = 0;
|
||||
if (err != LFS_ERR_NOENT) {
|
||||
err = lfsr_data_readleb128(lfs, &data, &block_size);
|
||||
if (err && err != LFS_ERR_CORRUPT) {
|
||||
return err;
|
||||
}
|
||||
if (err == LFS_ERR_CORRUPT) {
|
||||
block_size = -1;
|
||||
}
|
||||
lfsr_geometry_t geometry;
|
||||
err = lfsr_data_readgeometry(lfs, &data, &geometry);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (block_size != lfs->cfg->block_size-1) {
|
||||
if (geometry.block_size != lfs->cfg->block_size) {
|
||||
LFS_ERROR("Incompatible block size %"PRId32" (!= %"PRId32")",
|
||||
block_size+1,
|
||||
geometry.block_size,
|
||||
lfs->cfg->block_size);
|
||||
return LFS_ERR_INVAL;
|
||||
}
|
||||
|
||||
// check block count
|
||||
err = lfsr_mdir_lookup(lfs, mroot, LFSR_TAG_BLOCKCOUNT,
|
||||
&data);
|
||||
if (err && err != LFS_ERR_NOENT) {
|
||||
return err;
|
||||
}
|
||||
|
||||
uint32_t block_count = 0;
|
||||
if (err != LFS_ERR_NOENT) {
|
||||
err = lfsr_data_readleb128(lfs, &data, &block_count);
|
||||
if (err && err != LFS_ERR_CORRUPT) {
|
||||
return err;
|
||||
}
|
||||
if (err == LFS_ERR_CORRUPT) {
|
||||
block_count = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (block_count != lfs->cfg->block_count-1) {
|
||||
if (geometry.block_count != lfs->cfg->block_count) {
|
||||
LFS_ERROR("Incompatible block count %"PRId32" (!= %"PRId32")",
|
||||
block_count+1,
|
||||
geometry.block_count,
|
||||
lfs->cfg->block_count);
|
||||
return LFS_ERR_INVAL;
|
||||
}
|
||||
@@ -8280,11 +8313,10 @@ static int lfsr_formatinited(lfs_t *lfs) {
|
||||
LFSR_TAG_RCOMPAT, 0,
|
||||
LFSR_DATA_FROMRCOMPAT(LFSR_RCOMPAT_COMPAT)),
|
||||
LFSR_ATTR(
|
||||
LFSR_TAG_BLOCKSIZE, 0,
|
||||
LFSR_DATA_LEB128(lfs->cfg->block_size-1)),
|
||||
LFSR_ATTR(
|
||||
LFSR_TAG_BLOCKCOUNT, 0,
|
||||
LFSR_DATA_LEB128(lfs->cfg->block_count-1)),
|
||||
LFSR_TAG_GEOMETRY, 0,
|
||||
LFSR_DATA_FROMGEOMETRY((&(lfsr_geometry_t){
|
||||
lfs->cfg->block_size,
|
||||
lfs->cfg->block_count}))),
|
||||
LFSR_ATTR(
|
||||
LFSR_TAG_NAMELIMIT, 0,
|
||||
LFSR_DATA_LEB128(lfs->name_limit)),
|
||||
|
||||
+3
-4
@@ -17,10 +17,9 @@ TAG_VERSION = 0x0004
|
||||
TAG_RCOMPAT = 0x0005
|
||||
TAG_WCOMPAT = 0x0006
|
||||
TAG_OCOMPAT = 0x0007
|
||||
TAG_BLOCKSIZE = 0x0008
|
||||
TAG_BLOCKCOUNT = 0x0009
|
||||
TAG_NAMELIMIT = 0x000a
|
||||
TAG_SIZELIMIT = 0x000b
|
||||
TAG_GEOMETRY = 0x0009
|
||||
TAG_NAMELIMIT = 0x000c
|
||||
TAG_SIZELIMIT = 0x000d
|
||||
TAG_GDELTA = 0x0100
|
||||
TAG_GRMDELTA = 0x0100
|
||||
TAG_NAME = 0x0200
|
||||
|
||||
+4
-6
@@ -15,10 +15,9 @@ TAG_VERSION = 0x0004
|
||||
TAG_RCOMPAT = 0x0005
|
||||
TAG_WCOMPAT = 0x0006
|
||||
TAG_OCOMPAT = 0x0007
|
||||
TAG_BLOCKSIZE = 0x0008
|
||||
TAG_BLOCKCOUNT = 0x0009
|
||||
TAG_NAMELIMIT = 0x000a
|
||||
TAG_SIZELIMIT = 0x000b
|
||||
TAG_GEOMETRY = 0x0009
|
||||
TAG_NAMELIMIT = 0x000c
|
||||
TAG_SIZELIMIT = 0x000d
|
||||
TAG_GDELTA = 0x0100
|
||||
TAG_GRMDELTA = 0x0100
|
||||
TAG_NAME = 0x0200
|
||||
@@ -168,8 +167,7 @@ def tagrepr(tag, w, size, off=None):
|
||||
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 'geometry' if (tag & 0xfff) == TAG_GEOMETRY
|
||||
else 'sizelimit' if (tag & 0xfff) == TAG_SIZELIMIT
|
||||
else 'namelimit' if (tag & 0xfff) == TAG_NAMELIMIT
|
||||
else 'config 0x%02x' % (tag & 0xff),
|
||||
|
||||
+15
-26
@@ -16,10 +16,9 @@ TAG_VERSION = 0x0004
|
||||
TAG_RCOMPAT = 0x0005
|
||||
TAG_WCOMPAT = 0x0006
|
||||
TAG_OCOMPAT = 0x0007
|
||||
TAG_BLOCKSIZE = 0x0008
|
||||
TAG_BLOCKCOUNT = 0x0009
|
||||
TAG_NAMELIMIT = 0x000a
|
||||
TAG_SIZELIMIT = 0x000b
|
||||
TAG_GEOMETRY = 0x0009
|
||||
TAG_NAMELIMIT = 0x000c
|
||||
TAG_SIZELIMIT = 0x000d
|
||||
TAG_GDELTA = 0x0100
|
||||
TAG_GRMDELTA = 0x0100
|
||||
TAG_NAME = 0x0200
|
||||
@@ -199,8 +198,7 @@ def tagrepr(tag, w, size, off=None):
|
||||
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 'geometry' if (tag & 0xfff) == TAG_GEOMETRY
|
||||
else 'sizelimit' if (tag & 0xfff) == TAG_SIZELIMIT
|
||||
else 'namelimit' if (tag & 0xfff) == TAG_NAMELIMIT
|
||||
else 'config 0x%02x' % (tag & 0xff),
|
||||
@@ -1055,22 +1053,15 @@ class Config:
|
||||
return None
|
||||
|
||||
@ft.cached_property
|
||||
def block_size(self):
|
||||
if TAG_BLOCKSIZE in self.config:
|
||||
_, data = self.config[TAG_BLOCKSIZE]
|
||||
block_size, _ = fromleb128(data)
|
||||
return block_size
|
||||
def geometry(self):
|
||||
if TAG_GEOMETRY in self.config:
|
||||
_, data = self.config[TAG_GEOMETRY]
|
||||
d = 0
|
||||
block_size, d_ = fromleb128(data[d:]); d += d_
|
||||
block_count, d_ = fromleb128(data[d:]); d += d_
|
||||
return (block_size+1, block_count+1)
|
||||
else:
|
||||
return None
|
||||
|
||||
@ft.cached_property
|
||||
def block_count(self):
|
||||
if TAG_BLOCKCOUNT in self.config:
|
||||
_, data = self.config[TAG_BLOCKCOUNT]
|
||||
block_count, _ = fromleb128(data)
|
||||
return block_count
|
||||
else:
|
||||
return None
|
||||
return (None, None)
|
||||
|
||||
@ft.cached_property
|
||||
def name_limit(self):
|
||||
@@ -1107,10 +1098,8 @@ class Config:
|
||||
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:
|
||||
return 'blockcount %d' % self.block_count
|
||||
elif tag == TAG_GEOMETRY:
|
||||
return 'geometry %dx%d' % self.geometry
|
||||
elif tag == TAG_SIZELIMIT:
|
||||
return 'sizelimit %d' % self.size_limit
|
||||
elif tag == TAG_NAMELIMIT:
|
||||
@@ -1865,7 +1854,7 @@ def main(disk, mroots=None, *,
|
||||
print('littlefs v%s.%s %dx%d %s, rev %d, weight %d.%d' % (
|
||||
config.version[0] if config.version[0] is not None else '?',
|
||||
config.version[1] if config.version[1] is not None else '?',
|
||||
(config.block_size or -1)+1, (config.block_count or -1)+1,
|
||||
(config.geometry[0] or 0), (config.geometry[1] or 0),
|
||||
mroot.addr(), mroot.rev, bweight//mleaf_weight, 1*mleaf_weight))
|
||||
|
||||
# dynamically size the id field
|
||||
|
||||
+4
-6
@@ -15,10 +15,9 @@ TAG_VERSION = 0x0004
|
||||
TAG_RCOMPAT = 0x0005
|
||||
TAG_WCOMPAT = 0x0006
|
||||
TAG_OCOMPAT = 0x0007
|
||||
TAG_BLOCKSIZE = 0x0008
|
||||
TAG_BLOCKCOUNT = 0x0009
|
||||
TAG_NAMELIMIT = 0x000a
|
||||
TAG_SIZELIMIT = 0x000b
|
||||
TAG_GEOMETRY = 0x0009
|
||||
TAG_NAMELIMIT = 0x000c
|
||||
TAG_SIZELIMIT = 0x000d
|
||||
TAG_GDELTA = 0x0100
|
||||
TAG_GRMDELTA = 0x0100
|
||||
TAG_NAME = 0x0200
|
||||
@@ -183,8 +182,7 @@ def tagrepr(tag, w, size, off=None):
|
||||
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 'geometry' if (tag & 0xfff) == TAG_GEOMETRY
|
||||
else 'sizelimit' if (tag & 0xfff) == TAG_SIZELIMIT
|
||||
else 'namelimit' if (tag & 0xfff) == TAG_NAMELIMIT
|
||||
else 'config 0x%02x' % (tag & 0xff),
|
||||
|
||||
+4
-6
@@ -24,10 +24,9 @@ TAG_VERSION = 0x0004
|
||||
TAG_RCOMPAT = 0x0005
|
||||
TAG_WCOMPAT = 0x0006
|
||||
TAG_OCOMPAT = 0x0007
|
||||
TAG_BLOCKSIZE = 0x0008
|
||||
TAG_BLOCKCOUNT = 0x0009
|
||||
TAG_NAMELIMIT = 0x000a
|
||||
TAG_SIZELIMIT = 0x000b
|
||||
TAG_GEOMETRY = 0x0009
|
||||
TAG_NAMELIMIT = 0x000c
|
||||
TAG_SIZELIMIT = 0x000d
|
||||
TAG_GDELTA = 0x0100
|
||||
TAG_GRMDELTA = 0x0100
|
||||
TAG_NAME = 0x0200
|
||||
@@ -170,8 +169,7 @@ def tagrepr(tag, w, size, off=None):
|
||||
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 'geometry' if (tag & 0xfff) == TAG_GEOMETRY
|
||||
else 'sizelimit' if (tag & 0xfff) == TAG_SIZELIMIT
|
||||
else 'namelimit' if (tag & 0xfff) == TAG_NAMELIMIT
|
||||
else 'config 0x%02x' % (tag & 0xff),
|
||||
|
||||
Reference in New Issue
Block a user