Limited block_size and in-block types to 28-bits
One downside of leb128 encoding is that the worst case encoded size is
not that well aligned due to a relatively underutilized last byte:
0xffffffff => 0xff 0xff 0xff 0xff 0x0f
This normally doesn't really matter, the whole point of leb128 is that
larger encodings are statistically less likely. But in littlefs we need
to allocate the worst-case buffer size in order to encode/decode
leb128s, and these buffers need to stick around on the stack during
metadata commit calls, which are also the point of highest stack usage
in the system.
But 32-bits is somewhat arbitrary, it just happens to be our register
size. In fact, we're not really using 32-bits, but instead only 31-bits
to take advantage of the sign bit for ad-hoc sum types:
0x7fffffff => 0xff 0xff 0xff 0xff 0x07
In theory, if we limit this further to 28-bits, we could save some stack
space:
0x7fffffff => 0xff 0xff 0xff 0xff 0x07
0x0fffffff => 0xff 0xff 0xff 0x7f
This may seem like a small amount of savings, but it also restores
alignment to the encoding, and should result in less wasted padding
around buffers.
Though it's important to note these are the most valuable bits, as the
range grows exponentially with each bit added. Reducing 31-bits to
28-bits reduces the range from ~2GiB to ~256MiB:
0x7fffffff => 2,147,483,647
0x0fffffff => 268,435,455
---
At the moment I'm hesistant to reduce _all_ on-disk leb128s to 28-bits.
The signed-32-bit limit of ~2GiB is fairly well understood in this
space, mainly thanks to FAT, and reducing this to ~256MiB risks quite a
surprise to users (it's also a regression from the current littlefs
version).
But one type where this limit is pretty reasonable is our block_size.
I don't think we'll see devices with erase blocks >256MiB for a while,
and at the very least those devices will probably need a 64-bit
filesystem for other reasons anyways...
And limiting block_size to <=256MiB has a surprising number of knock-on
effects:
- The tag size/jump field never exceeds 28-bits, reducing worst-case tag
dsize from 12 bytes -> 11 bytes.
The also reduces our worst-case attr-estimate from 40 bytes ->
37 bytes
- rbyd/btree trunks never exceed 28-bits, saving space in shrub/branch/
btree encodings.
- The bptr encoding is reduced from 24 bytes -> 21 bytes, since several
of its fields are in-block (size, off, cksize).
- The commit checksum encoding is reduced by a byte for every commit,
from 12 bytes -> 11 bytes.
This is due to needing to expand the cksum tag's size field to the
worst possible leb128 encoding due to a catch-22 situation.
Unfortunately the actual stack savings is a bit underwhelming:
code stack
before: 33688 2808
after: 33700 (+0.0%) 2800 (-0.3%)
This may be because, by adopting 28-bits in only some fields, most
buffers still end up unaligned and the on-stack size doesn't change due
to padding. Or it could just be that I'm overestimating the cost of our
on-stack buffers.
Still, I think the change is worth keeping if only for the reducing
attr-estimate and saved byte on every on-disk commit.
In the future it would be interesting to explore additional
configurations, e.g. a 28-bit flavor of littlefs to compliment this
31-bit flavor. You could imagine the fitting into other register sized
flavors for different capacity/code cost/device compat tradeoffs:
flavor register leb128 size-limit
14-bit littlefs => 16-bit 2 bytes ~16KiB
15-bit littlefs => 16-bit 3 bytes ~32KiB
28-bit littlefs => 32-bit 4 bytes ~256MiB
31-bit littlefs => 32-bit 5 bytes ~2GiB
56-bit littlefs => 64-bit 8 bytes ~64PiB
63-bit littlefs => 64-bit 9 bytes ~8ExiB
This is where the on-disk size-limit attr would really shine.
---
Note we don't need an additional on-disk limit attr for the block_size.
We already store the block_size in the superblock, so we just need to
error if attempting to mount a filesystem with block_size >256MiB.
This commit is contained in:
@@ -891,11 +891,11 @@ static inline void lfsr_tag_trim2(
|
||||
// support for encoding/decoding tags on disk
|
||||
|
||||
// tag encoding:
|
||||
// .---+---+---+- -+- -+- -+- -+---+- -+- -+- -+- -. tag: 2 bytes
|
||||
// | tag | weight | size | weight: <=5 bytes
|
||||
// '---+---+---+- -+- -+- -+- -+---+- -+- -+- -+- -' size: <=5 bytes
|
||||
// total: <=12 bytes
|
||||
#define LFSR_TAG_DSIZE (2+5+5)
|
||||
// .---+---+---+- -+- -+- -+- -+---+- -+- -+- -. tag: 2 bytes
|
||||
// | tag | weight | size | weight: <=5 bytes
|
||||
// '---+---+---+- -+- -+- -+- -+---+- -+- -+- -' size: <=4 bytes
|
||||
// total: <=11 bytes
|
||||
#define LFSR_TAG_DSIZE (2+5+4)
|
||||
|
||||
static lfs_ssize_t lfsr_bd_readtag(lfs_t *lfs,
|
||||
lfs_block_t block, lfs_size_t off, lfs_size_t hint,
|
||||
@@ -936,6 +936,8 @@ static lfs_ssize_t lfsr_bd_readtag(lfs_t *lfs,
|
||||
if (d_ < 0) {
|
||||
return d_;
|
||||
}
|
||||
// weights should be limited to 31-bits
|
||||
LFS_ASSERT(weight <= 0x7fffffff);
|
||||
d += d_;
|
||||
|
||||
lfs_size_t size;
|
||||
@@ -943,6 +945,8 @@ static lfs_ssize_t lfsr_bd_readtag(lfs_t *lfs,
|
||||
if (d_ < 0) {
|
||||
return d_;
|
||||
}
|
||||
// sizes should be limited to 28-bits
|
||||
LFS_ASSERT(size <= 0x0fffffff);
|
||||
d += d_;
|
||||
|
||||
// optional checksum
|
||||
@@ -962,11 +966,12 @@ static lfs_ssize_t lfsr_bd_progtag(lfs_t *lfs,
|
||||
lfs_block_t block, lfs_size_t off,
|
||||
lfsr_tag_t tag, lfsr_rid_t weight, lfs_size_t size,
|
||||
uint32_t *cksum_) {
|
||||
// check for underflow issues
|
||||
LFS_ASSERT(weight < 0x80000000);
|
||||
LFS_ASSERT(size < 0x80000000);
|
||||
// bit 7 is reserved for future subtype extensions
|
||||
LFS_ASSERT(!(tag & 0x80));
|
||||
// weight should not exceed 31-bits
|
||||
LFS_ASSERT(weight <= 0x7fffffff);
|
||||
// size should not exceed 28-bits
|
||||
LFS_ASSERT(size <= 0x0fffffff);
|
||||
|
||||
// make sure to include the parity of the current crc
|
||||
tag |= (lfs_popc(*cksum_) & 1) << 15;
|
||||
@@ -975,15 +980,15 @@ static lfs_ssize_t lfsr_bd_progtag(lfs_t *lfs,
|
||||
uint8_t tag_buf[LFSR_TAG_DSIZE];
|
||||
tag_buf[0] = (uint8_t)(tag >> 8);
|
||||
tag_buf[1] = (uint8_t)(tag >> 0);
|
||||
|
||||
lfs_ssize_t d = 2;
|
||||
|
||||
lfs_ssize_t d_ = lfs_toleb128(weight, &tag_buf[d], 5);
|
||||
if (d_ < 0) {
|
||||
return d_;
|
||||
}
|
||||
d += d_;
|
||||
|
||||
d_ = lfs_toleb128(size, &tag_buf[d], 5);
|
||||
d_ = lfs_toleb128(size, &tag_buf[d], 4);
|
||||
if (d_ < 0) {
|
||||
return d_;
|
||||
}
|
||||
@@ -1237,6 +1242,7 @@ static int lfsr_data_readle32(lfs_t *lfs, lfsr_data_t *data,
|
||||
return 0;
|
||||
}
|
||||
|
||||
// note all leb128s in our system reserve the sign bit
|
||||
static int lfsr_data_readleb128(lfs_t *lfs, lfsr_data_t *data,
|
||||
uint32_t *word_) {
|
||||
// note we make sure not to update our data offset until after leb128
|
||||
@@ -1254,11 +1260,30 @@ static int lfsr_data_readleb128(lfs_t *lfs, lfsr_data_t *data,
|
||||
if (d < 0) {
|
||||
return d;
|
||||
}
|
||||
// all leb128s in our system reserve the sign bit
|
||||
LFS_ASSERT(*word_ <= 0x7fffffff);
|
||||
|
||||
*data = lfsr_data_slice(*data, d, -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// a little-leb128 in our system is truncated to align nicely
|
||||
//
|
||||
// for 32-bit words, little-leb128s are truncated to 28-bits, so the
|
||||
// resulting leb128 encoding fits nicely in 4-bytes
|
||||
static inline int lfsr_data_readlleb128(lfs_t *lfs, lfsr_data_t *data,
|
||||
uint32_t *word_) {
|
||||
// just call readleb128 here
|
||||
int err = lfsr_data_readleb128(lfs, data, word_);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// little-leb128s should be limited to 28-bits
|
||||
LFS_ASSERT(*word_ <= 0x0fffffff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static lfs_scmp_t lfsr_data_cmp(lfs_t *lfs, const lfsr_data_t *data,
|
||||
const void *buffer, lfs_size_t size) {
|
||||
// limit our size to data range
|
||||
@@ -1619,22 +1644,26 @@ static int lfsr_ecksum_validate(lfs_t *lfs, const lfsr_ecksum_t *ecksum,
|
||||
// erased-state checksum on-disk encoding
|
||||
|
||||
// ecksum encoding:
|
||||
// .---+- -+- -+- -+- -.
|
||||
// | cksize | cksize: <=5 bytes
|
||||
// +---+- -+- -+- -+- -'
|
||||
// | cksum | cksum: 4 bytes
|
||||
// '---+---+---+---' total: <=9 bytes
|
||||
// .---+- -+- -+- -.
|
||||
// | cksize | cksize: <=4 bytes
|
||||
// +---+- -+- -+- -+
|
||||
// | cksum | cksum: 4 bytes
|
||||
// '---+---+---+---' total: <=8 bytes
|
||||
//
|
||||
#define LFSR_ECKSUM_DSIZE (5+4)
|
||||
#define LFSR_ECKSUM_DSIZE (4+4)
|
||||
|
||||
#define LFSR_DATA_FROMECKSUM(_ecksum, _buffer) \
|
||||
lfsr_data_fromecksum(_ecksum, _buffer)
|
||||
|
||||
static lfsr_data_t lfsr_data_fromecksum(const lfsr_ecksum_t *ecksum,
|
||||
uint8_t buffer[static LFSR_ECKSUM_DSIZE]) {
|
||||
// you shouldn't try to encode a not-ecksum, that doesn't make sense
|
||||
LFS_ASSERT(ecksum->cksize != -1);
|
||||
// cksize should not exceed 28-bits
|
||||
LFS_ASSERT((uint32_t)ecksum->cksize <= 0x0fffffff);
|
||||
|
||||
lfs_ssize_t d = 0;
|
||||
lfs_ssize_t d_ = lfs_toleb128(ecksum->cksize, &buffer[d], 5);
|
||||
lfs_ssize_t d_ = lfs_toleb128(ecksum->cksize, &buffer[d], 4);
|
||||
LFS_ASSERT(d_ >= 0);
|
||||
d += d_;
|
||||
|
||||
@@ -1646,7 +1675,7 @@ static lfsr_data_t lfsr_data_fromecksum(const lfsr_ecksum_t *ecksum,
|
||||
|
||||
static int lfsr_data_readecksum(lfs_t *lfs, lfsr_data_t *data,
|
||||
lfsr_ecksum_t *ecksum) {
|
||||
int err = lfsr_data_readleb128(lfs, data, (uint32_t*)&ecksum->cksize);
|
||||
int err = lfsr_data_readlleb128(lfs, data, (uint32_t*)&ecksum->cksize);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
@@ -1663,29 +1692,37 @@ static int lfsr_data_readecksum(lfs_t *lfs, lfsr_data_t *data,
|
||||
// block pointer things
|
||||
|
||||
// bptr encoding:
|
||||
// .---+- -+- -+- -+- -.
|
||||
// | size | size: <=5 bytes
|
||||
// +---+- -+- -+- -+- -+
|
||||
// .---+- -+- -+- -.
|
||||
// | size | size: <=4 bytes
|
||||
// +---+- -+- -+- -+- -.
|
||||
// | block | block: <=5 bytes
|
||||
// +---+- -+- -+- -+- -+
|
||||
// | off | off: <=5 bytes
|
||||
// +---+- -+- -+- -+- -+
|
||||
// | cksize | cksize: <=5 bytes
|
||||
// +---+- -+- -+- -+- -'
|
||||
// | off | off: <=4 bytes
|
||||
// +---+- -+- -+- -+
|
||||
// | cksize | cksize: <=4 bytes
|
||||
// +---+- -+- -+- -+
|
||||
// | cksum | cksum: 4 bytes
|
||||
// '---+---+---+---' total: <=24 bytes
|
||||
// '---+---+---+---' total: <=21 bytes
|
||||
//
|
||||
#define LFSR_BPTR_DSIZE (5+5+5+5+4)
|
||||
#define LFSR_BPTR_DSIZE (4+5+4+4+4)
|
||||
|
||||
#define LFSR_DATA_FROMBPTR(_bptr, _buffer) \
|
||||
lfsr_data_frombptr(_bptr, _buffer)
|
||||
|
||||
static lfsr_data_t lfsr_data_frombptr(const lfsr_bptr_t *bptr,
|
||||
uint8_t buffer[static LFSR_BPTR_DSIZE]) {
|
||||
// size should not exceed 28-bits
|
||||
LFS_ASSERT(lfsr_data_size(&bptr->data) <= 0x0fffffff);
|
||||
// block should not exceed 31-bits
|
||||
LFS_ASSERT(bptr->data.u.disk.block <= 0x7fffffff);
|
||||
// off should not exceed 28-bits
|
||||
LFS_ASSERT(bptr->data.u.disk.off <= 0x0fffffff);
|
||||
// cksize should not exceed 28-bits
|
||||
LFS_ASSERT(bptr->cksize <= 0x0fffffff);
|
||||
lfs_ssize_t d = 0;
|
||||
|
||||
// write the block, offset, size
|
||||
lfs_ssize_t d_ = lfs_toleb128(lfsr_data_size(&bptr->data), &buffer[d], 5);
|
||||
lfs_ssize_t d_ = lfs_toleb128(lfsr_data_size(&bptr->data), &buffer[d], 4);
|
||||
LFS_ASSERT(d_ >= 0);
|
||||
d += d_;
|
||||
|
||||
@@ -1693,12 +1730,12 @@ static lfsr_data_t lfsr_data_frombptr(const lfsr_bptr_t *bptr,
|
||||
LFS_ASSERT(d_ >= 0);
|
||||
d += d_;
|
||||
|
||||
d_ = lfs_toleb128(bptr->data.u.disk.off, &buffer[d], 5);
|
||||
d_ = lfs_toleb128(bptr->data.u.disk.off, &buffer[d], 4);
|
||||
LFS_ASSERT(d_ >= 0);
|
||||
d += d_;
|
||||
|
||||
// write the cksize, cksum
|
||||
d_ = lfs_toleb128(bptr->cksize, &buffer[d], 5);
|
||||
d_ = lfs_toleb128(bptr->cksize, &buffer[d], 4);
|
||||
LFS_ASSERT(d_ >= 0);
|
||||
d += d_;
|
||||
|
||||
@@ -1711,7 +1748,7 @@ static lfsr_data_t lfsr_data_frombptr(const lfsr_bptr_t *bptr,
|
||||
static int lfsr_data_readbptr(lfs_t *lfs, lfsr_data_t *data,
|
||||
lfsr_bptr_t *bptr) {
|
||||
// read the block, offset, size
|
||||
int err = lfsr_data_readleb128(lfs, data,
|
||||
int err = lfsr_data_readlleb128(lfs, data,
|
||||
(uint32_t*)&bptr->data.u.disk.size);
|
||||
if (err) {
|
||||
return err;
|
||||
@@ -1722,13 +1759,13 @@ static int lfsr_data_readbptr(lfs_t *lfs, lfsr_data_t *data,
|
||||
return err;
|
||||
}
|
||||
|
||||
err = lfsr_data_readleb128(lfs, data, &bptr->data.u.disk.off);
|
||||
err = lfsr_data_readlleb128(lfs, data, &bptr->data.u.disk.off);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// read the cksize, cksum
|
||||
err = lfsr_data_readleb128(lfs, data, &bptr->cksize);
|
||||
err = lfsr_data_readlleb128(lfs, data, &bptr->cksize);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
@@ -1925,11 +1962,12 @@ static int lfsr_data_readgrm(lfs_t *lfs, lfsr_data_t *data,
|
||||
grm->rms[1] = -1;
|
||||
|
||||
// first read the mode field
|
||||
lfs_size_t mode;
|
||||
int err = lfsr_data_readleb128(lfs, data, &mode);
|
||||
if (err) {
|
||||
return err;
|
||||
uint8_t mode;
|
||||
lfs_ssize_t d = lfsr_data_read(lfs, data, &mode, 1);
|
||||
if (d < 0) {
|
||||
return d;
|
||||
}
|
||||
LFS_ASSERT(d == 1);
|
||||
|
||||
// unknown mode? return an error, we may be able to mount read-only
|
||||
if (mode > 2) {
|
||||
@@ -1937,12 +1975,11 @@ static int lfsr_data_readgrm(lfs_t *lfs, lfsr_data_t *data,
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < mode; i++) {
|
||||
err = lfsr_data_readleb128(lfs, data, (lfsr_mid_t*)&grm->rms[i]);
|
||||
int err = lfsr_data_readleb128(lfs, data, (uint32_t*)&grm->rms[i]);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
LFS_ASSERT(grm->rms[i] < lfs_smax32(
|
||||
LFS_ASSERT((uint32_t)grm->rms[i] < lfs_max32(
|
||||
lfsr_mtree_weight(&lfs->mtree),
|
||||
lfsr_mleafweight(lfs)));
|
||||
}
|
||||
@@ -3067,27 +3104,27 @@ static int lfsr_rbyd_appendcksum(lfs_t *lfs, lfsr_rbyd_t *rbyd) {
|
||||
// this gets a bit complicated as we have two types of cksums:
|
||||
//
|
||||
// - 9-word cksum with ecksum to check following prog (middle of block):
|
||||
// .---+---+---+---. ecksum tag: 2 bytes
|
||||
// | etag | 0 |esz| ecksum weight: 1 byte
|
||||
// +---+---+---+---+- -. ecksum size: 1 byte
|
||||
// | ecksize | ecksum cksize: <=5 bytes
|
||||
// +---+- -+- -+- -+- -' ecksum cksum: 4 bytes
|
||||
// .---+---+---+---. ecksum tag: 2 bytes
|
||||
// | etag | 0 |esz| ecksum weight: 1 byte
|
||||
// +---+---+---+---+ ecksum size: 1 byte
|
||||
// | ecksize | ecksum cksize: <=4 bytes
|
||||
// +---+- -+- -+- -+ ecksum cksum: 4 bytes
|
||||
// | ecksum |
|
||||
// +---+---+---+---+- -+- -+- -+- -. cksum tag: 2 bytes
|
||||
// | tag | 0 | size | cksum weight: 1 byte
|
||||
// +---+---+---+---+- -+- -+- -+- -' cksum size: <=5 bytes
|
||||
// | cksum | cksum cksum: 4 bytes
|
||||
// '---+---+---+---' total: <=25 bytes
|
||||
// +---+---+---+---+- -+- -+- -. cksum tag: 2 bytes
|
||||
// | tag | 0 | size | cksum weight: 1 byte
|
||||
// +---+---+---+---+- -+- -+- -' cksum size: <=4 bytes
|
||||
// | cksum | cksum cksum: 4 bytes
|
||||
// '---+---+---+---' total: <=23 bytes
|
||||
//
|
||||
// - 4-word cksum with no following prog (end of block):
|
||||
// .---+---+---+---+- -+- -+- -+- -. cksum tag: 2 bytes
|
||||
// | tag | 0 | size | cksum weight: 1 byte
|
||||
// +---+---+---+---+- -+- -+- -+- -' cksum size: <=5 bytes
|
||||
// | cksum | cksum cksum: 4 bytes
|
||||
// '---+---+---+---' total: <=12 bytes
|
||||
// .---+---+---+---+- -+- -+- -. cksum tag: 2 bytes
|
||||
// | tag | 0 | size | cksum weight: 1 byte
|
||||
// +---+---+---+---+- -+- -+- -' cksum size: <=4 bytes
|
||||
// | cksum | cksum cksum: 4 bytes
|
||||
// '---+---+---+---' total: <=11 bytes
|
||||
//
|
||||
lfs_size_t aligned_eoff = lfs_alignup(
|
||||
rbyd->eoff + 2+1+1+5+4 + 2+1+5+4,
|
||||
rbyd->eoff + 2+1+1+4+4 + 2+1+4+4,
|
||||
lfs->cfg->prog_size);
|
||||
|
||||
// space for ecksum?
|
||||
@@ -3131,7 +3168,7 @@ static int lfsr_rbyd_appendcksum(lfs_t *lfs, lfsr_rbyd_t *rbyd) {
|
||||
rbyd->eoff += lfsr_data_size(&ecksum_data);
|
||||
|
||||
// at least space for a cksum?
|
||||
} else if (rbyd->eoff + 2+1+5+4 <= lfs->cfg->block_size) {
|
||||
} else if (rbyd->eoff + 2+1+4+4 <= lfs->cfg->block_size) {
|
||||
// note this implicitly marks the rbyd as unerased
|
||||
aligned_eoff = lfs->cfg->block_size;
|
||||
|
||||
@@ -3145,36 +3182,35 @@ static int lfsr_rbyd_appendcksum(lfs_t *lfs, lfsr_rbyd_t *rbyd) {
|
||||
// note padding-size depends on leb-encoding depends on padding-size, to
|
||||
// get around this catch-22 we just always write a fully-expanded leb128
|
||||
// encoding
|
||||
uint8_t cksum_buf[2+1+5+4];
|
||||
uint8_t cksum_buf[2+1+4+4];
|
||||
cksum_buf[0] = (LFSR_TAG_CKSUM >> 8) | ((lfs_popc(rbyd->cksum) & 1) << 7);
|
||||
cksum_buf[1] = 0;
|
||||
cksum_buf[2] = 0;
|
||||
|
||||
lfs_size_t padding = aligned_eoff - (rbyd->eoff + 2+1+5);
|
||||
lfs_size_t padding = aligned_eoff - (rbyd->eoff + 2+1+4);
|
||||
cksum_buf[3] = 0x80 | (0x7f & (padding >> 0));
|
||||
cksum_buf[4] = 0x80 | (0x7f & (padding >> 7));
|
||||
cksum_buf[5] = 0x80 | (0x7f & (padding >> 14));
|
||||
cksum_buf[6] = 0x80 | (0x7f & (padding >> 21));
|
||||
cksum_buf[7] = 0x00 | (0x7f & (padding >> 28));
|
||||
cksum_buf[6] = 0x00 | (0x7f & (padding >> 21));
|
||||
|
||||
rbyd->cksum = lfs_crc32c(rbyd->cksum, cksum_buf, 2+1+5);
|
||||
rbyd->cksum = lfs_crc32c(rbyd->cksum, cksum_buf, 2+1+4);
|
||||
// we can't let the next tag appear as valid, so intentionally perturb the
|
||||
// commit if this happens, note parity(crc(m)) == parity(m) with crc32c,
|
||||
// so we can really change any bit to make this happen, we've reserved a bit
|
||||
// in cksum tags just for this purpose
|
||||
if ((lfs_popc(rbyd->cksum) & 1) == (perturb >> 7)) {
|
||||
cksum_buf[1] ^= 0x01;
|
||||
rbyd->cksum ^= 0x68032cc8; // note crc(a ^ b) == crc(a) ^ crc(b)
|
||||
rbyd->cksum ^= 0xef306b19; // note crc(a ^ b) == crc(a) ^ crc(b)
|
||||
}
|
||||
lfs_tole32_(rbyd->cksum, &cksum_buf[2+1+5]);
|
||||
lfs_tole32_(rbyd->cksum, &cksum_buf[2+1+4]);
|
||||
|
||||
int err = lfsr_bd_prog(lfs, rbyd->blocks[0], rbyd->eoff,
|
||||
cksum_buf, 2+1+5+4,
|
||||
cksum_buf, 2+1+4+4,
|
||||
NULL, NULL);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
rbyd->eoff += 2+1+5+4;
|
||||
rbyd->eoff += 2+1+4+4;
|
||||
|
||||
// flush our caches, finalizing the commit on-disk
|
||||
err = lfsr_bd_sync(lfs);
|
||||
@@ -3762,26 +3798,30 @@ static inline int lfsr_btree_cmp(
|
||||
// branch encoding:
|
||||
// .---+- -+- -+- -+- -.
|
||||
// | block | block: <=5 bytes
|
||||
// +---+- -+- -+- -+- -+
|
||||
// | trunk | trunk: <=5 bytes
|
||||
// +---+- -+- -+- -+- -'
|
||||
// | trunk | trunk: <=4 bytes
|
||||
// +---+- -+- -+- -+
|
||||
// | cksum | cksum: 4 bytes
|
||||
// '---+---+---+---' total: <=14 bytes
|
||||
// '---+---+---+---' total: <=13 bytes
|
||||
//
|
||||
#define LFSR_BRANCH_DSIZE (5+5+4)
|
||||
#define LFSR_BRANCH_DSIZE (5+4+4)
|
||||
|
||||
#define LFSR_DATA_FROMBRANCH(_branch, _buffer) \
|
||||
lfsr_data_frombranch(_branch, _buffer)
|
||||
|
||||
static lfsr_data_t lfsr_data_frombranch(const lfsr_rbyd_t *branch,
|
||||
uint8_t buffer[static LFSR_BRANCH_DSIZE]) {
|
||||
// block should not exceed 31-bits
|
||||
LFS_ASSERT(branch->blocks[0] <= 0x7fffffff);
|
||||
// trunk should not exceed 28-bits
|
||||
LFS_ASSERT(lfsr_rbyd_trunk(branch) <= 0x0fffffff);
|
||||
lfs_ssize_t d = 0;
|
||||
|
||||
lfs_ssize_t d_ = lfs_toleb128(branch->blocks[0], &buffer[d], 5);
|
||||
LFS_ASSERT(d_ >= 0);
|
||||
d += d_;
|
||||
|
||||
d_ = lfs_toleb128(lfsr_rbyd_trunk(branch), &buffer[d], 5);
|
||||
d_ = lfs_toleb128(lfsr_rbyd_trunk(branch), &buffer[d], 4);
|
||||
LFS_ASSERT(d_ >= 0);
|
||||
d += d_;
|
||||
|
||||
@@ -3804,7 +3844,7 @@ static int lfsr_data_readbranch(lfs_t *lfs, lfsr_data_t *data,
|
||||
return err;
|
||||
}
|
||||
|
||||
err = lfsr_data_readleb128(lfs, data, (uint32_t*)&branch->trunk);
|
||||
err = lfsr_data_readlleb128(lfs, data, (uint32_t*)&branch->trunk);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
@@ -3828,11 +3868,11 @@ static int lfsr_data_readbranch(lfs_t *lfs, lfsr_data_t *data,
|
||||
// | weight | weight: <=5 bytes
|
||||
// +---+- -+- -+- -+- -+
|
||||
// | block | block: <=5 bytes
|
||||
// +---+- -+- -+- -+- -+
|
||||
// | trunk | trunk: <=5 bytes
|
||||
// +---+- -+- -+- -+- -'
|
||||
// | trunk | trunk: <=4 bytes
|
||||
// +---+- -+- -+- -+
|
||||
// | cksum | cksum: 4 bytes
|
||||
// '---+---+---+---' total: <=19 bytes
|
||||
// '---+---+---+---' total: <=18 bytes
|
||||
//
|
||||
#define LFSR_BTREE_DSIZE (5+LFSR_BRANCH_DSIZE)
|
||||
|
||||
@@ -3841,7 +3881,10 @@ static int lfsr_data_readbranch(lfs_t *lfs, lfsr_data_t *data,
|
||||
|
||||
static lfsr_data_t lfsr_data_frombtree(const lfsr_btree_t *btree,
|
||||
uint8_t buffer[static LFSR_BTREE_DSIZE]) {
|
||||
// weight should not exceed 31-bits
|
||||
LFS_ASSERT(btree->weight <= 0x7fffffff);
|
||||
lfs_ssize_t d = 0;
|
||||
|
||||
lfs_ssize_t d_ = lfs_toleb128(btree->weight, &buffer[d], 5);
|
||||
LFS_ASSERT(d_ >= 0);
|
||||
d += d_;
|
||||
@@ -4886,11 +4929,11 @@ static inline int lfsr_shrub_cmp(
|
||||
// shrub encoding:
|
||||
// .---+- -+- -+- -+- -.
|
||||
// | weight | weight: <=5 bytes
|
||||
// +---+- -+- -+- -+- -+
|
||||
// | trunk | trunk: <=5 bytes
|
||||
// '---+- -+- -+- -+- -' total: <=10 bytes
|
||||
// +---+- -+- -+- -+- -'
|
||||
// | trunk | trunk: <=4 bytes
|
||||
// '---+- -+- -+- -' total: <=9 bytes
|
||||
//
|
||||
#define LFSR_SHRUB_DSIZE (5+5)
|
||||
#define LFSR_SHRUB_DSIZE (5+4)
|
||||
|
||||
#define LFSR_DATA_FROMSHRUB(_rbyd, _buffer) \
|
||||
lfsr_data_fromtrunk(_rbyd, _buffer)
|
||||
@@ -4899,6 +4942,10 @@ static lfsr_data_t lfsr_data_fromshrub(const lfsr_shrub_t *shrub,
|
||||
uint8_t buffer[static LFSR_SHRUB_DSIZE]) {
|
||||
// shrub trunks should never be null
|
||||
LFS_ASSERT(lfsr_shrub_trunk(shrub) != 0);
|
||||
// weight should not exceed 31-bits
|
||||
LFS_ASSERT(shrub->weight <= 0x7fffffff);
|
||||
// trunk should not exceed 28-bits
|
||||
LFS_ASSERT(lfsr_shrub_trunk(shrub) <= 0x0fffffff);
|
||||
lfs_ssize_t d = 0;
|
||||
|
||||
// just write the trunk and weight, the rest of the rbyd is contextual
|
||||
@@ -4906,7 +4953,7 @@ static lfsr_data_t lfsr_data_fromshrub(const lfsr_shrub_t *shrub,
|
||||
LFS_ASSERT(d_ >= 0);
|
||||
d += d_;
|
||||
|
||||
d_ = lfs_toleb128(lfsr_shrub_trunk(shrub), &buffer[d], 5);
|
||||
d_ = lfs_toleb128(lfsr_shrub_trunk(shrub), &buffer[d], 4);
|
||||
LFS_ASSERT(d_ >= 0);
|
||||
d += d_;
|
||||
|
||||
@@ -4926,7 +4973,7 @@ static int lfsr_data_readshrub(lfs_t *lfs, lfsr_data_t *data,
|
||||
return err;
|
||||
}
|
||||
|
||||
err = lfsr_data_readleb128(lfs, data, (uint32_t*)&shrub->trunk);
|
||||
err = lfsr_data_readlleb128(lfs, data, (uint32_t*)&shrub->trunk);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
@@ -5093,6 +5140,10 @@ static inline bool lfsr_mptr_ismrootanchor(const lfsr_mptr_t *mptr) {
|
||||
|
||||
static lfsr_data_t lfsr_data_frommptr(const lfsr_mptr_t *mptr,
|
||||
uint8_t buffer[static LFSR_MPTR_DSIZE]) {
|
||||
// blocks should not exceed 31-bits
|
||||
LFS_ASSERT(mptr->blocks[0] <= 0x7fffffff);
|
||||
LFS_ASSERT(mptr->blocks[1] <= 0x7fffffff);
|
||||
|
||||
lfs_ssize_t d = 0;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
lfs_ssize_t d_ = lfs_toleb128(mptr->blocks[i], &buffer[d], 5);
|
||||
@@ -14767,6 +14818,7 @@ failed:;
|
||||
|
||||
/// Filesystem operations ///
|
||||
static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
|
||||
// TODO this all needs to be cleaned up
|
||||
lfs->cfg = cfg;
|
||||
int err = 0;
|
||||
|
||||
@@ -14782,6 +14834,9 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
|
||||
LFS_ASSERT(lfs->cfg->cache_size % lfs->cfg->prog_size == 0);
|
||||
LFS_ASSERT(lfs->cfg->block_size % lfs->cfg->cache_size == 0);
|
||||
|
||||
// block_size is currently limited to 28-bits
|
||||
LFS_ASSERT(lfs->cfg->block_size <= 0x0fffffff);
|
||||
|
||||
// check that the block size is large enough to fit ctz pointers
|
||||
LFS_ASSERT(4*lfs_npw2(0xffffffff / (lfs->cfg->block_size-2*4))
|
||||
<= lfs->cfg->block_size);
|
||||
|
||||
Reference in New Issue
Block a user