Skip to content

Commit 1eeb2a6

Browse files
committed
Shrinked on-disk directory program size
Directories still consume two full erase blocks, but now only program the exact on-disk region to store the directory contents. This results in a decent improvement in the amount of data written and read to the device when doing directory operations. Calculating the checksum of dynamically sized data is surprisingly tricky, since the size of the data could also contain errors. For the littlefs, we can assume the data size must fit in an erase block. If the data size is invalid, we can just treat the block as corrupted.
1 parent 0d66f9f commit 1eeb2a6

File tree

2 files changed

+23
-34
lines changed

2 files changed

+23
-34
lines changed

Diff for: lfs.c

+21-32
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ static int lfs_dir_alloc(lfs_t *lfs, lfs_dir_t *dir) {
304304

305305
// set defaults
306306
dir->d.rev += 1;
307-
dir->d.size = sizeof(dir->d);
307+
dir->d.size = sizeof(dir->d)+4;
308308
dir->d.tail[0] = -1;
309309
dir->d.tail[1] = -1;
310310
dir->off = sizeof(dir->d);
@@ -331,17 +331,21 @@ static int lfs_dir_fetch(lfs_t *lfs,
331331
continue;
332332
}
333333

334+
if ((0x7fffffff & test.size) > lfs->cfg->block_size) {
335+
continue;
336+
}
337+
334338
uint32_t crc = 0xffffffff;
335339
crc = lfs_crc(crc, &test, sizeof(test));
336340

337-
for (lfs_off_t j = sizeof(test); j < lfs->cfg->block_size; j += 4) {
338-
uint32_t word;
339-
int err = lfs_read(lfs, tpair[i], j, &word, 4);
341+
for (lfs_off_t j = sizeof(test); j < (0x7fffffff & test.size); j++) {
342+
uint8_t data;
343+
int err = lfs_read(lfs, tpair[i], j, &data, 1);
340344
if (err) {
341345
return err;
342346
}
343347

344-
crc = lfs_crc(crc, &word, 4);
348+
crc = lfs_crc(crc, &data, 1);
345349
}
346350

347351
if (crc != 0) {
@@ -405,8 +409,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_dir_t *dir,
405409
int i = 0;
406410
lfs_off_t oldoff = sizeof(dir->d);
407411
lfs_off_t newoff = sizeof(dir->d);
408-
lfs_size_t newsize = 0x7fffffff & dir->d.size;
409-
while (newoff < newsize) {
412+
while (newoff < (0x7fffffff & dir->d.size)-4) {
410413
if (i < count && regions[i].oldoff == oldoff) {
411414
crc = lfs_crc(crc, regions[i].newdata, regions[i].newlen);
412415
int err = lfs_prog(lfs, dir->pair[0],
@@ -442,21 +445,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_dir_t *dir,
442445
}
443446
}
444447

445-
while (newoff < lfs->cfg->block_size-4) {
446-
uint8_t data = 0xff;
447-
crc = lfs_crc(crc, &data, 1);
448-
err = lfs_prog(lfs, dir->pair[0], newoff, &data, 1);
449-
if (err) {
450-
if (err == LFS_ERR_CORRUPT) {
451-
goto relocate;
452-
}
453-
return err;
454-
}
455-
456-
newoff += 1;
457-
}
458-
459-
err = lfs_prog(lfs, dir->pair[0], lfs->cfg->block_size-4, &crc, 4);
448+
err = lfs_prog(lfs, dir->pair[0], newoff, &crc, 4);
460449
if (err) {
461450
if (err == LFS_ERR_CORRUPT) {
462451
goto relocate;
@@ -514,8 +503,8 @@ static int lfs_dir_append(lfs_t *lfs, lfs_dir_t *dir,
514503
lfs_entry_t *entry, const void *data) {
515504
// check if we fit, if top bit is set we do not and move on
516505
while (true) {
517-
if (dir->d.size + entry->d.len <= lfs->cfg->block_size - 4) {
518-
entry->off = dir->d.size;
506+
if (dir->d.size + entry->d.len <= lfs->cfg->block_size) {
507+
entry->off = dir->d.size - 4;
519508
return lfs_dir_commit(lfs, dir, (struct lfs_region[]){
520509
{entry->off, 0, &entry->d, sizeof(entry->d)},
521510
{entry->off, 0, data, entry->d.len - sizeof(entry->d)}
@@ -532,7 +521,7 @@ static int lfs_dir_append(lfs_t *lfs, lfs_dir_t *dir,
532521

533522
newdir.d.tail[0] = dir->d.tail[0];
534523
newdir.d.tail[1] = dir->d.tail[1];
535-
entry->off = newdir.d.size;
524+
entry->off = newdir.d.size - 4;
536525
err = lfs_dir_commit(lfs, &newdir, (struct lfs_region[]){
537526
{entry->off, 0, &entry->d, sizeof(entry->d)},
538527
{entry->off, 0, data, entry->d.len - sizeof(entry->d)}
@@ -556,7 +545,7 @@ static int lfs_dir_append(lfs_t *lfs, lfs_dir_t *dir,
556545

557546
static int lfs_dir_remove(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) {
558547
// either shift out the one entry or remove the whole dir block
559-
if (dir->d.size == sizeof(dir->d)) {
548+
if (dir->d.size == sizeof(dir->d)+4) {
560549
lfs_dir_t pdir;
561550
int res = lfs_pred(lfs, dir->pair, &pdir);
562551
if (res < 0) {
@@ -580,7 +569,7 @@ static int lfs_dir_remove(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) {
580569
}
581570

582571
static int lfs_dir_next(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) {
583-
while (dir->off + sizeof(entry->d) > (0x7fffffff & dir->d.size)) {
572+
while (dir->off + sizeof(entry->d) > (0x7fffffff & dir->d.size)-4) {
584573
if (!(0x80000000 & dir->d.size)) {
585574
entry->off = dir->off;
586575
return LFS_ERR_NOENT;
@@ -592,7 +581,7 @@ static int lfs_dir_next(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) {
592581
}
593582

594583
dir->off = sizeof(dir->d);
595-
dir->pos += sizeof(dir->d);
584+
dir->pos += sizeof(dir->d) + 4;
596585
}
597586

598587
int err = lfs_read(lfs, dir->pair[0], dir->off,
@@ -1483,7 +1472,7 @@ int lfs_remove(lfs_t *lfs, const char *path) {
14831472
int err = lfs_dir_fetch(lfs, &dir, entry.d.u.dir);
14841473
if (err) {
14851474
return err;
1486-
} else if (dir.d.size != sizeof(dir.d)) {
1475+
} else if (dir.d.size != sizeof(dir.d)+4) {
14871476
return LFS_ERR_INVAL;
14881477
}
14891478
}
@@ -1559,7 +1548,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
15591548
int err = lfs_dir_fetch(lfs, &dir, preventry.d.u.dir);
15601549
if (err) {
15611550
return err;
1562-
} else if (dir.d.size != sizeof(dir.d)) {
1551+
} else if (dir.d.size != sizeof(dir.d)+4) {
15631552
return LFS_ERR_INVAL;
15641553
}
15651554
}
@@ -1733,7 +1722,7 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
17331722
};
17341723
superdir.d.tail[0] = root.pair[0];
17351724
superdir.d.tail[1] = root.pair[1];
1736-
superdir.d.size = sizeof(superdir.d) + sizeof(superblock.d);
1725+
superdir.d.size = sizeof(superdir.d) + sizeof(superblock.d) + 4;
17371726

17381727
// write both pairs to be safe
17391728
bool valid = false;
@@ -1832,7 +1821,7 @@ int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data) {
18321821
}
18331822

18341823
// iterate over contents
1835-
while ((0x7fffffff & dir.d.size) >= dir.off + sizeof(entry.d)) {
1824+
while (dir.off + sizeof(entry.d) <= (0x7fffffff & dir.d.size)-4) {
18361825
int err = lfs_read(lfs, dir.pair[0], dir.off,
18371826
&entry.d, sizeof(entry.d));
18381827
if (err) {

Diff for: tests/template.fmt

+2-2
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,11 @@ lfs_size_t rsize;
6161
uintmax_t res;
6262

6363
#ifndef LFS_READ_SIZE
64-
#define LFS_READ_SIZE 64
64+
#define LFS_READ_SIZE 16
6565
#endif
6666

6767
#ifndef LFS_PROG_SIZE
68-
#define LFS_PROG_SIZE 64
68+
#define LFS_PROG_SIZE 16
6969
#endif
7070

7171
#ifndef LFS_BLOCK_SIZE

0 commit comments

Comments
 (0)