Commit Graph

6 Commits

Author SHA1 Message Date
Christopher Haster
d08d254cd2 Switched to writing compat flags as le32s
Most of littlefs's metadata is encoded in leb128s now, with the
exception of tags (be16, sort of), revision counts (le32), cksums
(le32), and flags.

It makes sense for tags to be a special case, these are written and
rewritten _everywhere_, but less so for flags, which are only written to
the mroot and updated infrequently.

We might as well save a bit of code by reusing our le32 machinery.

---

This changes lfsr_format to just write out compat flags as le32s, saving
a tiny bit of code at the cost of a tiny bit of disk usage (the real
benefit being a tiny bit of code simplification):

           code          stack          ctx
  before: 37792           2608          620
  after:  37772 (-0.1%)   2608 (+0.0%)  620 (+0.0%)

Compat already need to handle trailing zeros gracefully, so this doesn't
change anything at mount time.

Also had to switch from enums to #defines thanks to C's broken enums.
Wooh. We already use #defines for the other flags for this reason.
2025-01-28 14:41:45 -06:00
Christopher Haster
e5609c98ec Renamed bsprout -> bmoss, bleaf -> bsprout
I just really don't like saying bleaf. Also I think the term moss
describes inlined data a bit better.
2025-01-28 14:41:45 -06:00
Christopher Haster
0cab73730e Added LFS_WCOMPAT_RDONLY and LFS_RCOMPAT_WRONLY
LFS_WCOMPAT_RDONLY seems generally useful for tools that just want to
mark a filesystem is read-only. This is a common flag that exists in
other filesystems (RO_COMPAT_READONLY in ext4 for example).

LFS_RCOMPAT_WRONLY, on the other hand, is a bit more of a joke, but
there could be some niche use cases for it (preventing double mounts?).

Fortunately, these flags require no extra code, and fall out naturally
from our wcompat/rcompat handling.

---

Originally, the idea was to also add LFS_F_RDONLY, to match LFS_M_RDONLY
and set the LFS_WCOMPAT_RDONLY flag during format.

But this doesn't really work with the current API, since lfsr_format
would just give you an empty filesystem you can't write to. Which is a
bit silly.

Maybe we should add something like lfsr_fs_mkrdonly in the future? This
is probably low-priority.
2025-01-28 14:41:45 -06:00
Christopher Haster
af6ea39cca Reworked rcompat flags
Mainly to add LFS_RCOMPAT_MSPROUT. It makes sense that a littlefs driver
may not want to support mroot-inlined mdirs, and this flag would be the
only way to indicate that. (Currently inlined mdir -> mtree is one way,
but this may not always be the case.)

This also makes space for a couple planned features:

  LFS_RCOMPAT_NONSTANDARD  0x00000001  Non-standard filesystem format
  LFS_RCOMPAT_WRONLY*      0x00000002  Reading is disallowed
  LFS_RCOMPAT_GRM          0x00000004  May use a global-remove
  LFS_RCOMPAT_MSPROUT      0x00000010  May use an inlined mdir
  LFS_RCOMPAT_MLEAF        0x00000020  May use a single mdir pointer
  LFS_RCOMPAT_MSHRUB       0x00000040  May use an inlined mtree
  LFS_RCOMPAT_MTREE        0x00000080  May use an mdir btree
  LFS_RCOMPAT_BSPROUT      0x00000100  Files may use inlined data
  LFS_RCOMPAT_BLEAF        0x00000200  Files may use single block pointers
  LFS_RCOMPAT_BSHRUB       0x00000400  Files may use inlined btrees
  LFS_RCOMPAT_BTREE        0x00000800  Files may use btrees

  *Planned

I've gone ahead and included rcompat flags we reserve but don't
currently use (LFS_RCOMPAT_MSHRUB). It seems like a good idea to make
these reservations explicit. Though we should still prohibit their use
until there is a good reason, in case we want to repurpose these flags
in the future.

Code changes minimal (larger literal? compiler noise?):

           code          stack          ctx
  before: 37788           2608          620
  after:  37792 (+0.0%)   2608 (+0.0%)  620 (+0.0%)
2025-01-28 14:41:45 -06:00
Christopher Haster
5f6dbdcb14 Reworked o/f/m/gc/i/t flags
This is mainly to free up space for flags, we're pretty close to running
out of 32-bits with future planned features:

1. Reduced file type info from 8 -> 4 bits

   We don't really need more than this, but it does mean type info is
   no longer a simple byte load.

2. Moved most internal file-state flags into the next 4 bits

   These are mostly file-type specific (except LFS_o_ZOMBIE), so we
   don't need to worry too much about overlap.

3. Compacted ck-flags into 5 bits:

     LFS_M_CKPROGS       0x00000800
     LFS_M_CKFETCHES     0x00001000
     LFS_M_CKPARITY      0x00002000
     LFS_M_CKMETAREDUND* 0x00004000
     LFS_M_CKDATACKSUMS  0x00008000

     *Planned

   Now that ck-flags are a bit more mature, it's pretty clear we'll
   probably never have CKMETACKSUMS (ckcksums + small tag reads is
   crazy expensive) or CKDATAREDUND (non-trivial parity fanout makes
   this crazy expensives. So reserving bits for these just wastes bits.

This also moves things around so ck-flags no longer overlap with open
flags.

It's a tight fit, and I still think file-specific ck-flags are out-of-
scope, but this at least decreases flag ambiguity.

New jenga:

              8     8     8     8
            .----++----++----++----.
            .-..-..-.-------.------.
  o_flags:  |t||f||t|       |  o   |
            |-||-||-|-------:--.---'
            |-||-||-'--.----.------.
  t_flags:  |t||f|| t  |    | tstt |
            '-''-'|----|----'------'
            .----.|----|.--.:--:.--.
  m_flags:  | f  || t  ||c ||o ||m |
            |----||-.--'|--|'--''--'
            |----||-|---|--|.------.
  f_flags:  | f  ||t|   |c ||  f   |
            '----''-'---'--''------'

Fortunately no major code costs:

           code          stack          ctx
  before: 37792           2608          620
  after:  37788 (-0.0%)   2608 (+0.0%)  620 (+0.0%)
2025-01-28 14:41:45 -06:00
Christopher Haster
726bf86d21 Added dbgflags.py for easier flag debugging
dbgerr.py and dbgtag.py have proven to be incredibly useful for quick
debugging/introspection, so I figured why not have more of that.

My favorite part is being able to quickly see all flags set on an open
file handle:

  (gdb) p file.o.o.flags
  $2 = 24117517
  (gdb) !./scripts/dbgflags.py o 24117517
  LFS_O_WRONLY   0x00000001  Open a file as write only
  LFS_O_CREAT    0x00000004  Create a file if it does not exist
  LFS_O_EXCL     0x00000008  Fail if a file already exists
  LFS_O_DESYNC   0x00000100  Do not sync or recieve file updates
  LFS_o_REG      0x01000000  Type = regular-file
  LFS_o_UNFLUSH  0x00100000  File's data does not match disk
  LFS_o_UNSYNC   0x00200000  File's metadata does not match disk
  LFS_o_UNCREAT  0x00400000  File does not exist yet

The only concern is if dbgflags.py falls out-of-sync often, I suspect
flag encoding will have quite a bit more churn than flags/tags. But we
can always drop this script in the future if this turns into a problem.

---

While poking around this also ended up with a bunch of other small
changes:

- Added LFS_*_MODE masks for consistency with other "type<->flag
  embeddings"

- Added compat flag comments

- Adopted lowercase prefix for internal flags (LFS_o_ZOMBIE), though
  not sure if I'll keep this yet...

- Tweaked dbgerr.py to also match ERR_ prefixes and to ignore case
2025-01-28 14:41:45 -06:00