Removed clamping to block size in ctz linked-list

Initially, I was concerned that the number of pointers in the ctz
linked-list could exceed the storage in a block. Long story short
this isn't really possible outside of extremely small block sizes.

Since clamping impacts the layout of files on disk, removing the
block size removed quite a bit of logic and corner cases. Replaced
with an assert on block size during initialization.

---

Long story long, the minimum block size needed to store all ctz
pointers in a filesystem can be found with this formula:

B = (w/8)*log2(2^w / (B - 2*(w/8)))

where:
B = block size in bytes
w = pointer width in bits

It's not a very pretty formula, but does give us some useful info
if we apply some math:

min block size:
32 bit ctz linked-list = 104 bytes
64 bit ctz linked-list = 448 bytes

For littlefs, 128 bytes is a perfectly reasonable minimum block size.
This commit is contained in:
Christopher Haster
2017-10-10 18:48:24 -05:00
parent 83d4c614a0
commit f3578e3250

13
lfs.c
View File

@@ -1005,12 +1005,11 @@ int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir) {
/// File index list operations /// /// File index list operations ///
static int lfs_index(lfs_t *lfs, lfs_off_t *off) { static int lfs_index(lfs_t *lfs, lfs_off_t *off) {
lfs_off_t i = 0; lfs_off_t i = 0;
lfs_size_t words = lfs->cfg->block_size / 4;
while (*off >= lfs->cfg->block_size) { while (*off >= lfs->cfg->block_size) {
i += 1; i += 1;
*off -= lfs->cfg->block_size; *off -= lfs->cfg->block_size;
*off += 4*lfs_min(lfs_ctz(i)+1, words-1); *off += 4*(lfs_ctz(i) + 1);
} }
return i; return i;
@@ -1028,12 +1027,11 @@ static int lfs_index_find(lfs_t *lfs,
lfs_off_t current = lfs_index(lfs, &(lfs_off_t){size-1}); lfs_off_t current = lfs_index(lfs, &(lfs_off_t){size-1});
lfs_off_t target = lfs_index(lfs, &pos); lfs_off_t target = lfs_index(lfs, &pos);
lfs_size_t words = lfs->cfg->block_size / 4;
while (current > target) { while (current > target) {
lfs_size_t skip = lfs_min( lfs_size_t skip = lfs_min(
lfs_npw2(current-target+1) - 1, lfs_npw2(current-target+1) - 1,
lfs_min(lfs_ctz(current)+1, words-1) - 1); lfs_ctz(current));
int err = lfs_cache_read(lfs, rcache, pcache, head, 4*skip, &head, 4); int err = lfs_cache_read(lfs, rcache, pcache, head, 4*skip, &head, 4);
if (err) { if (err) {
@@ -1102,8 +1100,7 @@ static int lfs_index_extend(lfs_t *lfs,
// append block // append block
index += 1; index += 1;
lfs_size_t words = lfs->cfg->block_size / 4; lfs_size_t skips = lfs_ctz(index) + 1;
lfs_size_t skips = lfs_min(lfs_ctz(index)+1, words-1);
for (lfs_off_t i = 0; i < skips; i++) { for (lfs_off_t i = 0; i < skips; i++) {
int err = lfs_cache_prog(lfs, pcache, rcache, int err = lfs_cache_prog(lfs, pcache, rcache,
@@ -1880,6 +1877,10 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
} }
} }
// check that the block size is large enough to fit ctz pointers
assert(4*lfs_npw2(0xffffffff / (lfs->cfg->block_size-2*4))
<= lfs->cfg->block_size);
// setup default state // setup default state
lfs->root[0] = 0xffffffff; lfs->root[0] = 0xffffffff;
lfs->root[1] = 0xffffffff; lfs->root[1] = 0xffffffff;