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:
Christopher Haster
2024-03-18 02:15:46 -05:00
parent 796be705ac
commit 9366674416
6 changed files with 105 additions and 91 deletions
+75 -43
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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),