Files
littlefs/scripts/dbgerr.py
Christopher Haster 635e1fe8d4 t: Added lookahead to lfsr_traversal_t, adopted in lfs_alloc
This sort of turned into a complete refactor of lfs_alloc in order to
move/reuse the lookahead buffer filling logic into lfsr_fs_traverse.

lfs_alloc now calls lfsr_fs_traverse to fill the lookahead buffer when
no more blocks are available, but also you can too with lfsr_traversal_t
+ LFS_T_LOOKAHEAD.

The one big caveat being if any mutation happens to the filesystem, any
incomplete lookahead needs to be tossed out. To help with this,
lfsr_traversal_read now returns LFS_ERR_BUSY (-16) instead of
LFS_ERR_NOENT (-2) if the filesystem has been modified since the
traversal was opened.

Note that by default lfsr_traversal_t will still try to keep traversing
blocks, but can be told to terminate immediately with LFS_T_EXCL.
Continuing the traversal is probably desired for checking checksums,
debugging, etc, as otherwise you could end up looping over only the
first couple blocks in a write-heavy system, but if you are trying to
populate the lookahead buffer you probably want to just abort and start
over.

I considered adding a flags field to lfs_tinfo for this, but decided
against it since it would be the only place in the current API where we
don't use error codes to convey behavior-changing information. Though
this may be worth reconsidering at some point...

---

In reworking lfs_alloc, a lot of the internal logic was broken up into
specific functions:

- lfs_alloc_ckpoint - checkpoint the allocator
- lfs_alloc_discard - discard any lookahead
- lfs_alloc_shift - discard/shift lookahead if progress can be made
- lfs_alloc_markinuse - mark a block as in-use
- lfs_alloc_markfree - mark any remaining blocks as free
- lfs_alloc_findnext - find the next free block in lookahead

If anything this probably makes lfs_alloc more readable, though the
original motivation was to allow lfsr_traversal_t to only shift/zero the
lookahead buffer if there's a chance we can make progress.

This was based on upstream work by opilat and myself.

Code changes:

           code          stack
  before: 34226           2560
  after:  34474 (+0.7%)   2552 (-0.3%)
2024-06-20 13:11:41 -05:00

98 lines
3.3 KiB
Python
Executable File

#!/usr/bin/env python3
ERRS = [
('OK', 0, "No error" ),
('UNKNOWN', -1, "Unknown error" ),
('INVAL', -22, "Invalid parameter" ),
('NOTSUP', -95, "Operation not supported" ),
('BUSY', -16, "Device or resource busy" ),
('IO', -5, "Error during device operation" ),
('CORRUPT', -84, "Corrupted" ),
('NOENT', -2, "No directory entry" ),
('EXIST', -17, "Entry already exists" ),
('NOTDIR', -20, "Entry is not a dir" ),
('ISDIR', -21, "Entry is a dir" ),
('NOTEMPTY', -39, "Dir is not empty" ),
('FBIG', -27, "File too large" ),
('NOSPC', -28, "No space left on device" ),
('NOMEM', -12, "No more memory available" ),
('NOATTR', -61, "No data/attr available" ),
('NAMETOOLONG', -36, "File name too long" ),
('RANGE', -34, "Result out of range" ),
]
def main(errs, *,
list=False):
list_, list = list, __builtins__.list
# list all known error codes
if list_:
# first find the widths
w = [0, 0]
for n, e, h in ERRS:
w[0] = max(w[0], len('LFS_ERR_')+len(n))
w[1] = max(w[1], len(str(e)))
# print
for n, e, h in ERRS:
print('%-*s %-*s %s' % (
w[0], 'LFS_ERR_'+n,
w[1], e,
h))
# find these errors
else:
def find_err(err):
# find by LFS_ERR_+name
for n, e, h in ERRS:
if 'LFS_ERR_'+n == err:
return n, e, h
# find by name
for n, e, h in ERRS:
if n == err:
return n, e, h
# find by E+name
for n, e, h in ERRS:
if 'E'+n == err:
return n, e, h
try:
# find by err code
for n, e, h in ERRS:
if e == int(err, 0):
return n, e, h
# find by negated err code
for n, e, h in ERRS:
if e == -int(err, 0):
return n, e, h
except ValueError:
pass
# not found
raise KeyError(err)
for err in errs:
try:
n, e, h = find_err(err)
print('%s %s %s' % ('LFS_ERR_'+n, e, h))
except KeyError:
print('%s ?' % err)
if __name__ == "__main__":
import argparse
import sys
parser = argparse.ArgumentParser(
description="Decode littlefs error codes.",
allow_abbrev=False)
parser.add_argument(
'errs',
nargs='*',
help="Error codes or error names to decode.")
parser.add_argument(
'-l', '--list',
action='store_true',
help="List all known error codes.")
sys.exit(main(**{k: v
for k, v in vars(parser.parse_intermixed_args()).items()
if v is not None}))