Added LFS_T_RDONLY, LFS_T_RDWR, etc

These mimic the relevant LFS_O_* flags, and allow users to assert
whether or not a traversal will mutate the filesystem:

  LFS_T_MODE          0x00000001  The traversal's access mode
  LFS_T_RDWR          0x00000000  Open traversal as read and write
  LFS_T_RDONLY        0x00000001  Open traversal as read only

In theory, these could also change internal allocations, but littlefs
doesn't really work that way.

Note we _don't_ add related LFS_GC_RDONLY, LFS_GC_RDWR, etc flags. These
are sort of implied by the relevant LFS_M_* flags.

Adds a bit more code, probably because of the slightly more complicated
internal constants for the internal traversals. But I think the
self-documentingness is worth it:

           code          stack          ctx
  before: 37200           2288          636
  after:  37220 (+0.1%)   2288 (+0.0%)  636 (+0.0%)
This commit is contained in:
Christopher Haster
2025-05-24 22:57:35 -05:00
parent 5b74aafa17
commit f7e17c8aad
9 changed files with 249 additions and 150 deletions
+24 -13
View File
@@ -7052,6 +7052,10 @@ static inline bool lfsr_a_islazy(uint32_t flags) {
}
// traversal flags
static inline bool lfsr_t_isrdonly(uint32_t flags) {
return flags & LFS_T_RDONLY;
}
static inline bool lfsr_t_ismtreeonly(uint32_t flags) {
return flags & LFS_T_MTREEONLY;
}
@@ -10259,7 +10263,7 @@ static lfs_sblock_t lfs_alloc(lfs_t *lfs, bool erase) {
// in-use in the next lookahead window
//
lfsr_traversal_t t;
lfsr_traversal_init(&t, LFS_T_LOOKAHEAD);
lfsr_traversal_init(&t, LFS_T_RDONLY | LFS_T_LOOKAHEAD);
while (true) {
lfsr_tag_t tag;
lfsr_bptr_t bptr;
@@ -13753,7 +13757,8 @@ int lfsr_file_ckmeta(lfs_t *lfs, lfsr_file_t *file) {
// can't read from writeonly files
LFS_ASSERT(!lfsr_o_iswronly(file->b.o.flags));
return lfsr_file_ck(lfs, file, LFS_T_CKMETA);
return lfsr_file_ck(lfs, file,
LFS_T_RDONLY | LFS_T_CKMETA);
}
int lfsr_file_ckdata(lfs_t *lfs, lfsr_file_t *file) {
@@ -13761,7 +13766,8 @@ int lfsr_file_ckdata(lfs_t *lfs, lfsr_file_t *file) {
// can't read from writeonly files
LFS_ASSERT(!lfsr_o_iswronly(file->b.o.flags));
return lfsr_file_ck(lfs, file, LFS_T_CKMETA | LFS_T_CKDATA);
return lfsr_file_ck(lfs, file,
LFS_T_RDONLY | LFS_T_CKMETA | LFS_T_CKDATA);
}
@@ -14453,7 +14459,7 @@ static int lfsr_mountinited(lfs_t *lfs) {
// mdirs are valid if we haven't checked the btree inner nodes at
// least once?
lfsr_traversal_t t;
lfsr_traversal_init(&t, LFS_T_MTREEONLY | LFS_T_CKMETA);
lfsr_traversal_init(&t, LFS_T_RDONLY | LFS_T_MTREEONLY | LFS_T_CKMETA);
while (true) {
lfsr_tag_t tag;
lfsr_bptr_t bptr;
@@ -14970,7 +14976,7 @@ int lfsr_fs_stat(lfs_t *lfs, struct lfs_fsinfo *fsinfo) {
lfs_ssize_t lfsr_fs_usage(lfs_t *lfs) {
lfs_size_t count = 0;
lfsr_traversal_t t;
lfsr_traversal_init(&t, 0);
lfsr_traversal_init(&t, LFS_T_RDONLY);
while (true) {
lfsr_tag_t tag;
lfsr_bptr_t bptr;
@@ -15107,7 +15113,8 @@ failed:;
static int lfsr_fs_fixorphans(lfs_t *lfs) {
// LFS_T_MKCONSISTENT really just removes orphans
lfsr_traversal_t t;
lfsr_traversal_init(&t, LFS_T_MTREEONLY | LFS_T_MKCONSISTENT);
lfsr_traversal_init(&t,
LFS_T_RDWR | LFS_T_MTREEONLY | LFS_T_MKCONSISTENT);
while (true) {
lfsr_bptr_t bptr;
int err = lfsr_mtree_gc(lfs, &t,
@@ -15172,11 +15179,11 @@ static int lfsr_fs_ck(lfs_t *lfs, uint32_t flags) {
}
int lfsr_fs_ckmeta(lfs_t *lfs) {
return lfsr_fs_ck(lfs, LFS_T_CKMETA);
return lfsr_fs_ck(lfs, LFS_T_RDONLY | LFS_T_CKMETA);
}
int lfsr_fs_ckdata(lfs_t *lfs) {
return lfsr_fs_ck(lfs, LFS_T_CKMETA | LFS_T_CKDATA);
return lfsr_fs_ck(lfs, LFS_T_RDONLY | LFS_T_CKMETA | LFS_T_CKDATA);
}
// get the filesystem checksum
@@ -15398,16 +15405,20 @@ int lfsr_traversal_open(lfs_t *lfs, lfsr_traversal_t *t, uint32_t flags) {
LFS_ASSERT(!lfsr_omdir_isopen(lfs, &t->b.o));
// unknown flags?
LFS_ASSERT((flags & ~(
LFS_T_MTREEONLY
LFS_T_RDONLY
| LFS_T_RDWR
| LFS_T_MTREEONLY
| LFS_T_MKCONSISTENT
| LFS_T_LOOKAHEAD
| LFS_T_COMPACT
| LFS_T_CKMETA
| LFS_T_CKDATA)) == 0);
// these flags require a writable filesystem
LFS_ASSERT(!lfsr_m_isrdonly(lfs->flags) || !lfsr_t_ismkconsistent(flags));
LFS_ASSERT(!lfsr_m_isrdonly(lfs->flags) || !lfsr_t_islookahead(flags));
LFS_ASSERT(!lfsr_m_isrdonly(lfs->flags) || !lfsr_t_iscompact(flags));
// writeable traversals require a writeable filesystem
LFS_ASSERT(!lfsr_m_isrdonly(lfs->flags) || lfsr_t_isrdonly(flags));
// these flags require a writable traversal
LFS_ASSERT(!lfsr_t_isrdonly(flags) || !lfsr_t_ismkconsistent(flags));
LFS_ASSERT(!lfsr_t_isrdonly(flags) || !lfsr_t_islookahead(flags));
LFS_ASSERT(!lfsr_t_isrdonly(flags) || !lfsr_t_iscompact(flags));
// some flags don't make sense when only traversing the mtree
LFS_ASSERT(!lfsr_t_ismtreeonly(flags) || !lfsr_t_islookahead(flags));
LFS_ASSERT(!lfsr_t_ismtreeonly(flags) || !lfsr_t_isckdata(flags));