Increased internal flags 16 bits -> 32 bits

If we add CKMETA/CKDATA and eventually REPAIRMETA/REPAIRDATA to the file
open flags, we'll end up with 17 flags total (13 user-facing,
4 internal), which is a bit (heh) too much for a 16-bit flags field!

There are a few ways to solve this, dropping features for one, instead
I've decided to expand the fields flag to 32-bits. Fortunately this was
already the field size for all user-facing fields.

To avoid a RAM increase, I've also shoved the opened-file types and
traversal tstates into the same field.

We have various flags in quite a few places now, here's how
everything fits together:

              8     8     8     8
            .----++----++----++----.
            .----..---..--..-------.
  o_flags:  |type|| f ||t ||   o   |
            |----||---|:--:'-------'
            |----||---|:--:--------.
  d_flags:  |type|| f |:  :        |
            |----||---|:--:--------'
            |----||---|:--'--..----.
  t_flags:  |type|| f ||  t  ||tstt|
            '----''---'|-----|'----'
            .----------|-----|-----.
  gc_flags: |          |  t  |     |
            '----------|-----|-----'
            .-----.---.|-----|.----.
  m_flags:  |     | m ||  t  || m  |
            '-----|---|'-----'|----|
            .----.|---|-------|----|
  i_flags:  | i  || m |       | m  |
            '----''---'-------'----'

Unfortunately, using the full 32-bit flag space highlights that C99's
enum types are kind of garbage...

In C99 enums are strictly signed ints, which means attempting to use
them for 32-bit bit fields overflows. There is no way around this so
I've switched our flag definitions to #defines.

I've kept types as enums for now but I'm keeping my eye on them...

---

The tradeoff of merging the type/btype/tstate/flags fields is that it
takes more code to extract/encode the various subfields. Since these
fields our heavily used in our codebase, this really adds up:

           code          stack
  before: 35888           2696
  after:  36048 (+0.4%)   2696 (+0.0%)

At least in theory the type fields can be optimized to a byte load, but
not btype/tstate. Also accessing bits in higher positions may be adding
cost.
This commit is contained in:
Christopher Haster
2024-07-25 14:05:04 -05:00
parent 35db3bc97f
commit 0893c1f6be
3 changed files with 318 additions and 296 deletions
+75 -87
View File
@@ -113,35 +113,6 @@ enum lfs_error {
LFS_ERR_RANGE = -34, // Result out of range
};
// Filesystem mount flags
enum lfs_mount_flags {
LFS_M_RDWR = 0x0000, // Mount the filesystem as read and write
LFS_M_RDONLY = 0x0001, // Mount the filesystem as read only
LFS_M_CKPROGS = 0x0008, // Check progs by reading back progged data
LFS_M_MTREEONLY = 0x0010, // Only traverse the mtree
LFS_M_MKCONSISTENT = 0x0020, // Make the filesystem consistent
LFS_M_LOOKAHEAD = 0x0040, // Populate lookahead buffer
LFS_M_COMPACT = 0x0080, // Compact metadata logs
LFS_M_CKMETA = 0x0100, // Check metadata checksums
LFS_M_CKDATA = 0x0200, // Check metadata + data checksums
};
// Filesystem info flags
enum lfs_fsinfo_flags {
// mount flags
LFS_I_RDONLY = 0x0001, // Filesystem mounted read only
LFS_I_CKPROGS = 0x0008, // Check progs by reading back progged data
// state flags
LFS_I_INCONSISTENT = 0x0100, // Filesystem needs mkconsistent to write
LFS_I_CANLOOKAHEAD = 0x0400, // Lookahead buffer is not full
LFS_I_UNCOMPACTED = 0x1000, // Filesystem may have uncompacted metadata
// internally used flags
LFS_F_ORPHANS = 0x8000, // Filesystem may have untracked orphans
};
// File types
enum lfs_type {
// file types
@@ -155,75 +126,94 @@ enum lfs_type {
};
// File open flags
enum lfs_open_flags {
// open flags
LFS_O_RDONLY = 0, // Open a file as read only
#ifndef LFS_READONLY
LFS_O_WRONLY = 1, // Open a file as write only
LFS_O_RDWR = 2, // Open a file as read and write
LFS_O_CREAT = 0x0004, // Create a file if it does not exist
LFS_O_EXCL = 0x0008, // Fail if a file already exists
LFS_O_TRUNC = 0x0010, // Truncate the existing file to zero size
LFS_O_APPEND = 0x0020, // Move to end of file on every write
LFS_O_FLUSH = 0x0040, // Flush data on every write
LFS_O_SYNC = 0x0080, // Sync metadata on every write
LFS_O_DESYNC = 0x0100, // Do not sync or recieve file updates
#endif
#define LFS_O_RDONLY 0 // Open a file as read only
#define LFS_O_WRONLY 1 // Open a file as write only
#define LFS_O_RDWR 2 // Open a file as read and write
#define LFS_O_CREAT 0x00000004 // Create a file if it does not exist
#define LFS_O_EXCL 0x00000008 // Fail if a file already exists
#define LFS_O_TRUNC 0x00000010 // Truncate the existing file to zero size
#define LFS_O_APPEND 0x00000020 // Move to end of file on every write
#define LFS_O_FLUSH 0x00000040 // Flush data on every write
#define LFS_O_SYNC 0x00000080 // Sync metadata on every write
#define LFS_O_DESYNC 0x00000100 // Do not sync or recieve file updates
// internally used flags
LFS_F_UNFLUSH = 0x1000, // File's data does not match disk
LFS_F_UNSYNC = 0x2000, // File's metadata does not match disk
LFS_F_ORPHAN = 0x4000, // File does not exist
LFS_F_ZOMBIE = 0x8000, // File has been removed
};
// internally used flags
#define LFS_F_TYPE 0xff000000 // The file's type
#define LFS_F_UNFLUSH 0x00100000 // File's data does not match disk
#define LFS_F_UNSYNC 0x00200000 // File's metadata does not match disk
#define LFS_F_ORPHAN 0x00400000 // File does not exist
#define LFS_F_ZOMBIE 0x00800000 // File has been removed
// File seek flags
enum lfs_whence_flags {
LFS_SEEK_SET = 0, // Seek relative to an absolute position
LFS_SEEK_CUR = 1, // Seek relative to the current file position
LFS_SEEK_END = 2, // Seek relative to the end of the file
};
#define LFS_SEEK_SET 0 // Seek relative to an absolute position
#define LFS_SEEK_CUR 1 // Seek relative to the current file position
#define LFS_SEEK_END 2 // Seek relative to the end of the file
// Filesystem mount flags
#define LFS_M_RDWR 0 // Mount the filesystem as read and write
#define LFS_M_RDONLY 1 // Mount the filesystem as read only
#define LFS_M_CKPROGS 0x00000010 // Check progs by reading back progged data
#define LFS_M_MTREEONLY \
0x00010000 // Only traverse the mtree
#define LFS_M_MKCONSISTENT \
0x00000100 // Make the filesystem consistent
#define LFS_M_LOOKAHEAD \
0x00000200 // Populate lookahead buffer
#define LFS_M_COMPACT 0x00000800 // Compact metadata logs
#define LFS_M_CKMETA 0x00001000 // Check metadata checksums
#define LFS_M_CKDATA 0x00002000 // Check metadata + data checksums
// internally used flags
#define LFS_F_ORPHANS 0x01000000 // Filesystem may have untracked orphans
#define LFS_F_UNCOMPACTED \
0x08000000 // Filesystem may have uncompacted metadata
// Filesystem info flags
#define LFS_I_RDONLY 0x00000001 // Filesystem mounted read only
#define LFS_I_CKPROGS 0x00000010 // Check progs by reading back progged data
#define LFS_I_INCONSISTENT \
0x01000000 // Filesystem needs mkconsistent to write
#define LFS_I_CANLOOKAHEAD \
0x02000000 // Lookahead buffer is not full
#define LFS_I_UNCOMPACTED \
0x08000000 // Filesystem may have uncompacted metadata
// Block types
enum lfs_btype {
LFS_BTYPE_MDIR = 1,
LFS_BTYPE_BTREE = 2,
LFS_BTYPE_DATA = 3,
// TODO
// LFS_BTYPE_PARITY = 4,
// LFS_BTYPE_BAD = 5,
};
// Traversal flags
enum lfs_traversal_flags {
// traversal open flags
LFS_T_MTREEONLY = 0x0010, // Only traverse the mtree
LFS_T_MKCONSISTENT = 0x0020, // Make the filesystem consistent
LFS_T_LOOKAHEAD = 0x0040, // Populate lookahead buffer
LFS_T_COMPACT = 0x0080, // Compact metadata logs
LFS_T_CKMETA = 0x0100, // Check metadata checksums
LFS_T_CKDATA = 0x0200, // Check metadata + data checksums
// TODO
// LFS_T_REPAIRMETA = 0x0400, // Repair metadata blocks
// LFS_T_REPAIRDATA = 0x0800, // Repair metadata + data blocks
#define LFS_T_MTREEONLY \
0x00010000 // Only traverse the mtree
#define LFS_T_MKCONSISTENT \
0x00000100 // Make the filesystem consistent
#define LFS_T_LOOKAHEAD \
0x00000200 // Populate lookahead buffer
#define LFS_T_COMPACT 0x00000800 // Compact metadata logs
#define LFS_T_CKMETA 0x00001000 // Check metadata checksums
#define LFS_T_CKDATA 0x00002000 // Check metadata + data checksums
// internally used flags
LFS_F_DIRTY = 0x1000, // Filesystem modified during traversal
LFS_F_MUTATED = 0x4000, // Filesystem modified by traversal
};
// internally used flags
#define LFS_F_TSTATE 0x0000000f // The current traversal state
#define LFS_F_BTYPE 0x000000f0 // The current traversal btype
#define LFS_F_DIRTY 0x00040000 // Filesystem modified during traversal
#define LFS_F_MUTATED 0x00080000 // Filesystem modified by traversal
// GC flags
enum lfs_gc_flags {
LFS_GC_MTREEONLY = 0x0010, // Only traverse the mtree
LFS_GC_MKCONSISTENT = 0x0020, // Make the filesystem consistent
LFS_GC_LOOKAHEAD = 0x0040, // Populate lookahead buffer
LFS_GC_COMPACT = 0x0080, // Compact metadata logs
LFS_GC_CKMETA = 0x0100, // Check metadata checksums
LFS_GC_CKDATA = 0x0200, // Check metadata + data checksums
// TODO
// LFS_GC_REPAIRMETA = 0x0400, // Repair metadata blocks
// LFS_GC_REPAIRDATA = 0x0800, // Repair metadata + data blocks
};
#define LFS_GC_MTREEONLY \
0x00010000 // Only traverse the mtree
#define LFS_GC_MKCONSISTENT \
0x00000100 // Make the filesystem consistent
#define LFS_GC_LOOKAHEAD \
0x00000200 // Populate lookahead buffer
#define LFS_GC_COMPACT 0x00000800 // Compact metadata logs
#define LFS_GC_CKMETA 0x00001000 // Check metadata checksums
#define LFS_GC_CKDATA 0x00002000 // Check metadata + data checksums
// Configuration provided during initialization of the littlefs
@@ -522,9 +512,7 @@ typedef struct lfsr_mdir {
typedef struct lfsr_omdir {
struct lfsr_omdir *next;
uint8_t type;
uint8_t state;
uint16_t flags;
uint32_t flags;
lfsr_mdir_t mdir;
} lfsr_omdir_t;
@@ -723,7 +711,7 @@ typedef struct lfsr_grm {
// The littlefs filesystem type
typedef struct lfs {
const struct lfs_config *cfg;
uint16_t flags;
uint32_t flags;
lfs_size_t block_count;
lfs_size_t name_limit;
lfs_off_t file_limit;