mirror of
https://github.com/littlefs-project/littlefs.git
synced 2025-11-16 12:34:34 +00:00
With the relaxation of traversal behavior under mutation, I think it
makes sense to bring back LFS3_T_EXCL. If only to allow traversals to
gaurantee termination under mutation. Now that traversals no longer
guarantee forward progress, it's possible to get stuck looping
indefinitely if the filesystem is constantly being mutated.
Non-excl traversals are probably still useful for GC work and debugging
threads, but LFS3_T_EXCL now allows traversals to terminate immediately
with LFS3_ERR_BUSY at the first sign of unrelated filesystem mutation:
LFS3_T_EXCL 0x00000008 Error if filesystem modified
Internally, we already track unrelated mutation to avoid corrupt state
(LFS3_t_DIRTY), so this is a very low-cost feature:
code stack ctx
before: 35944 2280 660
after: 35964 (+0.1%) 2280 (+0.0%) 660 (+0.0%)
code stack ctx
gbmap before: 38916 2296 772
gbmap after: 38940 (+0.1%) 2296 (+0.0%) 772 (+0.0%)
code stack ctx
gc before: 36016 2280 768
gc after: 36036 (+0.1%) 2280 (+0.0%) 768 (+0.0%)
174 lines
5.0 KiB
Python
Executable File
174 lines
5.0 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
# prevent local imports
|
|
if __name__ == "__main__":
|
|
__import__('sys').path.pop(0)
|
|
|
|
import functools as ft
|
|
|
|
|
|
# Error codes
|
|
ERR_OK = 0 # No error
|
|
ERR_UNKNOWN = -1 # Unknown error
|
|
ERR_INVAL = -22 # Invalid parameter
|
|
ERR_NOTSUP = -95 # Operation not supported
|
|
ERR_BUSY = -16 # Device or resource busy
|
|
ERR_IO = -5 # Error during device operation
|
|
ERR_CORRUPT = -84 # Corrupted
|
|
ERR_NOENT = -2 # No directory entry
|
|
ERR_EXIST = -17 # Entry already exists
|
|
ERR_NOTDIR = -20 # Entry is not a dir
|
|
ERR_ISDIR = -21 # Entry is a dir
|
|
ERR_NOTEMPTY = -39 # Dir is not empty
|
|
ERR_FBIG = -27 # File too large
|
|
ERR_NOSPC = -28 # No space left on device
|
|
ERR_NOMEM = -12 # No more memory available
|
|
ERR_NOATTR = -61 # No data/attr available
|
|
ERR_NAMETOOLONG = -36 # File name too long
|
|
ERR_RANGE = -34 # Result out of range
|
|
|
|
|
|
# self-parsing error codes
|
|
class Err:
|
|
def __init__(self, name, code, help):
|
|
self.name = name
|
|
self.code = code
|
|
self.help = help
|
|
|
|
def __repr__(self):
|
|
return 'Err(%r, %r, %r)' % (
|
|
self.name,
|
|
self.code,
|
|
self.help)
|
|
|
|
def __eq__(self, other):
|
|
return self.name == other.name
|
|
|
|
def __ne__(self, other):
|
|
return self.name != other.name
|
|
|
|
def __hash__(self):
|
|
return hash(self.name)
|
|
|
|
def line(self):
|
|
return ('LFS3_%s' % self.name, '%d' % self.code, self.help)
|
|
|
|
@staticmethod
|
|
@ft.cache
|
|
def errs():
|
|
# parse our script's source to figure out errs
|
|
import inspect
|
|
import re
|
|
errs = []
|
|
err_pattern = re.compile(
|
|
'^(?P<name>ERR_[^ ]*) *= *(?P<code>[^#]*?) *'
|
|
'#+ *(?P<help>.*)$')
|
|
for line in (inspect.getsource(
|
|
inspect.getmodule(inspect.currentframe()))
|
|
.replace('\\\n', '')
|
|
.splitlines()):
|
|
m = err_pattern.match(line)
|
|
if m:
|
|
errs.append(Err(
|
|
m.group('name'),
|
|
globals()[m.group('name')],
|
|
m.group('help')))
|
|
return errs
|
|
|
|
|
|
def main(errs, *,
|
|
list=False):
|
|
import builtins
|
|
list_, list = list, builtins.list
|
|
|
|
# find errs
|
|
errs__ = Err.errs()
|
|
|
|
lines = []
|
|
# list all known error codes
|
|
if list_:
|
|
for e in errs__:
|
|
lines.append(e.line())
|
|
|
|
# find errs by name or value
|
|
else:
|
|
for e_ in errs:
|
|
found = False
|
|
# find by LFS3_ERR_+name
|
|
for e in errs__:
|
|
if 'LFS3_%s' % e.name.upper() == e_.upper():
|
|
lines.append(e.line())
|
|
found = True
|
|
if found:
|
|
continue
|
|
# find by ERR_+name
|
|
for e in errs__:
|
|
if e.name.upper() == e_.upper():
|
|
lines.append(e.line())
|
|
found = True
|
|
if found:
|
|
continue
|
|
# find by name
|
|
for e in errs__:
|
|
if e.name.split('_', 1)[1] == e_.upper():
|
|
lines.append(e.line())
|
|
found = True
|
|
if found:
|
|
continue
|
|
# find by E+name
|
|
for e in errs__:
|
|
if 'E%s' % e.name.split('_', 1)[1].upper() == e_.upper():
|
|
lines.append(e.line())
|
|
found = True
|
|
if found:
|
|
continue
|
|
try:
|
|
# find by err code
|
|
for e in errs__:
|
|
if e.code == int(e_, 0):
|
|
lines.append(e.line())
|
|
found = True
|
|
if found:
|
|
continue
|
|
# find by negated err code
|
|
for e in errs__:
|
|
if e.code == -int(e_, 0):
|
|
lines.append(e.line())
|
|
found = True
|
|
if found:
|
|
continue
|
|
except ValueError:
|
|
lines.append(('?', e_, 'Unknown err code'))
|
|
|
|
# first find widths
|
|
w = [0, 0]
|
|
for l in lines:
|
|
w[0] = max(w[0], len(l[0]))
|
|
w[1] = max(w[1], len(l[1]))
|
|
|
|
# then print results
|
|
for l in lines:
|
|
print('%-*s %-*s %s' % (
|
|
w[0], l[0],
|
|
w[1], l[1],
|
|
l[2]))
|
|
|
|
|
|
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}))
|