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
This commit is contained in:
Christopher Haster
2025-01-09 15:26:08 -06:00
parent 9ed9cf0ccd
commit 726bf86d21
6 changed files with 429 additions and 104 deletions
+66 -66
View File
@@ -6549,11 +6549,11 @@ static int lfsr_data_readmptr(lfs_t *lfs, lfsr_data_t *data,
// open flags
static inline bool lfsr_o_isrdonly(uint32_t flags) {
return (flags & 3) == LFS_O_RDONLY;
return (flags & LFS_O_MODE) == LFS_O_RDONLY;
}
static inline bool lfsr_o_iswronly(uint32_t flags) {
return (flags & 3) == LFS_O_WRONLY;
return (flags & LFS_O_MODE) == LFS_O_WRONLY;
}
static inline bool lfsr_o_iscreat(uint32_t flags) {
@@ -6607,19 +6607,19 @@ static inline bool lfsr_o_isbshrub(uint32_t flags) {
}
static inline bool lfsr_o_isunflush(uint32_t flags) {
return flags & LFS_O_UNFLUSH;
return flags & LFS_o_UNFLUSH;
}
static inline bool lfsr_o_isunsync(uint32_t flags) {
return flags & LFS_O_UNSYNC;
return flags & LFS_o_UNSYNC;
}
static inline bool lfsr_o_isuncreat(uint32_t flags) {
return flags & LFS_O_UNCREAT;
return flags & LFS_o_UNCREAT;
}
static inline bool lfsr_o_iszombie(uint32_t flags) {
return flags & LFS_O_ZOMBIE;
return flags & LFS_o_ZOMBIE;
}
// custom rat flags
@@ -6670,11 +6670,11 @@ static inline uint32_t lfsr_t_setbtype(uint32_t flags, uint8_t btype) {
}
static inline bool lfsr_t_isdirty(uint32_t flags) {
return flags & LFS_T_DIRTY;
return flags & LFS_t_DIRTY;
}
static inline bool lfsr_t_ismutated(uint32_t flags) {
return flags & LFS_T_MUTATED;
return flags & LFS_t_MUTATED;
}
static inline uint32_t lfsr_t_swapdirty(uint32_t flags) {
@@ -6721,7 +6721,7 @@ static inline bool lfsr_m_issync(uint32_t flags) {
// internal fs flags
static inline bool lfsr_i_isuntidy(uint32_t flags) {
return flags & LFS_I_UNTIDY;
return flags & LFS_i_UNTIDY;
}
static inline bool lfsr_i_iscompact(uint32_t flags) {
@@ -6804,7 +6804,7 @@ static void lfsr_omdir_clobber(lfs_t *lfs, const lfsr_omdir_t *o,
bool dirty) {
for (lfsr_omdir_t *o_ = lfs->omdirs; o_; o_ = o_->next) {
if (lfsr_o_type(o_->flags) == LFS_TYPE_TRAVERSAL) {
o_->flags |= (dirty) ? LFS_T_DIRTY : 0;
o_->flags |= (dirty) ? LFS_t_DIRTY : 0;
if (o && ((lfsr_traversal_t*)o_)->ot == o) {
lfsr_traversal_clobber(lfs, (lfsr_traversal_t*)o_);
@@ -8744,7 +8744,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
if (o->mdir.mid < mid_ - rats[i].weight) {
// we should not be removing opened regular files
LFS_ASSERT(lfsr_o_type(o->flags) != LFS_TYPE_REG);
o->flags |= LFS_O_ZOMBIE;
o->flags |= LFS_o_ZOMBIE;
o->mdir.mid = mid_;
} else {
o->mdir.mid += rats[i].weight;
@@ -9554,7 +9554,7 @@ dropped:;
}
// make sure we clear any zombie flags
t->o.o.flags &= ~LFS_O_ZOMBIE;
t->o.o.flags &= ~LFS_o_ZOMBIE;
// did this drop our mdir?
if (mdir->mid != -1 && mdir->rbyd.weight == 0) {
@@ -9623,7 +9623,7 @@ eot:;
// was mkconsistent successful?
if (lfsr_t_ismkconsistent(t->o.o.flags)
&& !lfsr_t_isdirty(t->o.o.flags)) {
lfs->flags &= ~LFS_I_UNTIDY;
lfs->flags &= ~LFS_i_UNTIDY;
}
// was compaction successful? note we may need multiple passes if
@@ -10008,9 +10008,9 @@ int lfsr_mkdir(lfs_t *lfs, const char *path) {
if (exists
&& lfsr_o_type(o->flags) == LFS_TYPE_REG
&& o->mdir.mid == mdir.mid) {
o->flags = (o->flags & ~LFS_O_UNCREAT)
| LFS_O_ZOMBIE
| LFS_O_UNSYNC
o->flags = (o->flags & ~LFS_o_UNCREAT)
| LFS_o_ZOMBIE
| LFS_o_UNSYNC
| LFS_O_DESYNC;
// update dir positions
@@ -10158,23 +10158,23 @@ int lfsr_remove(lfs_t *lfs, const char *path) {
if (zombie
&& lfsr_o_type(o->flags) == LFS_TYPE_REG
&& o->mdir.mid == mdir.mid) {
o->flags |= LFS_O_UNCREAT
| LFS_O_ZOMBIE
| LFS_O_UNSYNC
o->flags |= LFS_o_UNCREAT
| LFS_o_ZOMBIE
| LFS_o_UNSYNC
| LFS_O_DESYNC;
// mark any removed dirs as zombied
} else if (did_
&& lfsr_o_type(o->flags) == LFS_TYPE_DIR
&& ((lfsr_dir_t*)o)->did == did_) {
o->flags |= LFS_O_ZOMBIE;
o->flags |= LFS_o_ZOMBIE;
// update dir positions
} else if (lfsr_o_type(o->flags) == LFS_TYPE_DIR
&& ((lfsr_dir_t*)o)->did == did
&& o->mdir.mid >= mdir.mid) {
if (lfsr_o_iszombie(o->flags)) {
o->flags &= ~LFS_O_ZOMBIE;
o->flags &= ~LFS_o_ZOMBIE;
} else {
((lfsr_dir_t*)o)->pos -= 1;
}
@@ -10182,7 +10182,7 @@ int lfsr_remove(lfs_t *lfs, const char *path) {
// clobber entangled traversals
} else if (lfsr_o_type(o->flags) == LFS_TYPE_TRAVERSAL) {
if (lfsr_o_iszombie(o->flags)) {
o->flags &= ~LFS_O_ZOMBIE;
o->flags &= ~LFS_o_ZOMBIE;
o->mdir.mid -= 1;
lfsr_traversal_clobber(lfs, (lfsr_traversal_t*)o);
}
@@ -10324,9 +10324,9 @@ int lfsr_rename(lfs_t *lfs, const char *old_path, const char *new_path) {
if (exists
&& lfsr_o_type(o->flags) == LFS_TYPE_REG
&& o->mdir.mid == new_mdir.mid) {
o->flags = (o->flags & ~LFS_O_UNCREAT)
| LFS_O_ZOMBIE
| LFS_O_UNSYNC
o->flags = (o->flags & ~LFS_o_UNCREAT)
| LFS_o_ZOMBIE
| LFS_o_UNSYNC
| LFS_O_DESYNC;
// update moved files with the new mdir
@@ -10338,7 +10338,7 @@ int lfsr_rename(lfs_t *lfs, const char *old_path, const char *new_path) {
} else if (new_did_
&& lfsr_o_type(o->flags) == LFS_TYPE_DIR
&& ((lfsr_dir_t*)o)->did == new_did_) {
o->flags |= LFS_O_ZOMBIE;
o->flags |= LFS_o_ZOMBIE;
// update dir positions
} else if (lfsr_o_type(o->flags) == LFS_TYPE_DIR) {
@@ -10878,7 +10878,7 @@ static int lfsr_file_fetch(lfs_t *lfs, lfsr_file_t *file, bool trunc) {
file->buffer.pos = 0;
file->buffer.size = 0;
// mark as flushed
file->o.o.flags &= ~LFS_O_UNFLUSH;
file->o.o.flags &= ~LFS_o_UNFLUSH;
// don't bother reading disk if we're not created or truncating
if (!lfsr_o_isuncreat(file->o.o.flags) && !trunc) {
@@ -10929,7 +10929,7 @@ static int lfsr_file_fetch(lfs_t *lfs, lfsr_file_t *file, bool trunc) {
file->o.bshrub = file->o.bshrub_;
// mark as synced
file->o.o.flags &= ~LFS_O_UNSYNC;
file->o.o.flags &= ~LFS_o_UNSYNC;
}
// if our file is small, try to keep the whole thing in our buffer
@@ -10945,7 +10945,7 @@ static int lfsr_file_fetch(lfs_t *lfs, lfsr_file_t *file, bool trunc) {
}
// small files remain perpetually unflushed
file->o.o.flags |= LFS_O_UNFLUSH;
file->o.o.flags |= LFS_o_UNFLUSH;
lfsr_bshrub_init(&file->o.bshrub);
file->buffer.pos = 0;
file->buffer.size = size;
@@ -11051,7 +11051,7 @@ int lfsr_file_opencfg(lfs_t *lfs, lfsr_file_t *file,
// mounted with LFS_M_FLUSH/SYNC? implies LFS_O_FLUSH/SYNC
| (lfs->flags & (LFS_M_FLUSH | LFS_M_SYNC))
// default to unflushed for orphans/truncated files
| LFS_O_UNFLUSH;
| LFS_o_UNFLUSH;
file->pos = 0;
file->eblock = 0;
file->eoff = -1;
@@ -11087,7 +11087,7 @@ int lfsr_file_opencfg(lfs_t *lfs, lfsr_file_t *file,
if (exists
&& lfsr_o_isexcl(flags)
&& lfsr_omdir_ismidopen(lfs, file->o.o.mdir.mid,
~(LFS_O_ZOMBIE | LFS_O_DESYNC))) {
~(LFS_o_ZOMBIE | LFS_O_DESYNC))) {
return LFS_ERR_EXIST;
}
@@ -11121,7 +11121,7 @@ int lfsr_file_opencfg(lfs_t *lfs, lfsr_file_t *file,
// mark as uncreated and unsynced, we need to convert to reg file
// on first sync
file->o.o.flags |= LFS_O_UNCREAT | LFS_O_UNSYNC;
file->o.o.flags |= LFS_o_UNCREAT | LFS_o_UNSYNC;
} else {
// wanted to create a new entry?
@@ -11204,7 +11204,7 @@ static void lfsr_file_close_(lfs_t *lfs, const lfsr_file_t *file) {
// fallback to just marking the filesystem as untidy
} else {
lfs->flags |= LFS_I_UNTIDY;
lfs->flags |= LFS_i_UNTIDY;
}
}
}
@@ -12287,7 +12287,7 @@ lfs_ssize_t lfsr_file_write(lfs_t *lfs, lfsr_file_t *file,
// checkpoint the allocator
lfs_alloc_ckpoint(lfs);
// mark as unsynced in case we fail
file->o.o.flags |= LFS_O_UNSYNC;
file->o.o.flags |= LFS_o_UNSYNC;
// update pos if we are appending
lfs_off_t pos = file->pos;
@@ -12334,7 +12334,7 @@ lfs_ssize_t lfsr_file_write(lfs_t *lfs, lfsr_file_t *file,
lfsr_file_buffersize(lfs, file));
file->buffer.size = lfsr_file_buffersize(lfs, file);
file->o.o.flags &= ~LFS_O_UNFLUSH;
file->o.o.flags &= ~LFS_o_UNFLUSH;
written += size;
pos += size;
buffer_ += size;
@@ -12377,7 +12377,7 @@ lfs_ssize_t lfsr_file_write(lfs_t *lfs, lfsr_file_t *file,
file->buffer.size,
pos+d - file->buffer.pos);
file->o.o.flags |= LFS_O_UNFLUSH;
file->o.o.flags |= LFS_o_UNFLUSH;
written += d;
pos += d;
buffer_ += d;
@@ -12391,7 +12391,7 @@ lfs_ssize_t lfsr_file_write(lfs_t *lfs, lfsr_file_t *file,
if (err) {
goto failed;
}
file->o.o.flags &= ~LFS_O_UNFLUSH;
file->o.o.flags &= ~LFS_o_UNFLUSH;
}
// update our pos
@@ -12461,7 +12461,7 @@ int lfsr_file_flush(lfs_t *lfs, lfsr_file_t *file) {
}
// mark as flushed
file->o.o.flags &= ~LFS_O_UNFLUSH;
file->o.o.flags &= ~LFS_o_UNFLUSH;
return 0;
failed:;
@@ -12635,19 +12635,19 @@ int lfsr_file_sync(lfs_t *lfs, lfsr_file_t *file) {
&& o != &file->o.o) {
lfsr_file_t *file_ = (lfsr_file_t*)o;
// notify all files of creation
file_->o.o.flags &= ~LFS_O_UNCREAT;
file_->o.o.flags &= ~LFS_o_UNCREAT;
// mark desynced files an unsynced
if (lfsr_o_isdesync(file_->o.o.flags)) {
file_->o.o.flags |= LFS_O_UNSYNC;
file_->o.o.flags |= LFS_o_UNSYNC;
// update synced files
} else {
file_->o.o.flags &= ~LFS_O_UNSYNC;
file_->o.o.flags &= ~LFS_o_UNSYNC;
if (lfsr_o_isunflush(file->o.o.flags)) {
file_->o.o.flags |= LFS_O_UNFLUSH;
file_->o.o.flags |= LFS_o_UNFLUSH;
} else {
file_->o.o.flags &= ~LFS_O_UNFLUSH;
file_->o.o.flags &= ~LFS_o_UNFLUSH;
}
file_->o.bshrub = file->o.bshrub;
file_->buffer.pos = file->buffer.pos;
@@ -12699,7 +12699,7 @@ int lfsr_file_sync(lfs_t *lfs, lfsr_file_t *file) {
}
// mark as synced
file->o.o.flags &= ~(LFS_O_UNSYNC | LFS_O_UNCREAT | LFS_O_DESYNC);
file->o.o.flags &= ~(LFS_o_UNSYNC | LFS_o_UNCREAT | LFS_O_DESYNC);
return 0;
failed:;
@@ -12819,7 +12819,7 @@ int lfsr_file_truncate(lfs_t *lfs, lfsr_file_t *file, lfs_off_t size_) {
// checkpoint the allocator
lfs_alloc_ckpoint(lfs);
// mark as unsynced in case we fail
file->o.o.flags |= LFS_O_UNSYNC;
file->o.o.flags |= LFS_o_UNSYNC;
// does our file become small?
if (size_ <= lfsr_file_inlinesize(lfs, file)) {
@@ -12854,7 +12854,7 @@ int lfsr_file_truncate(lfs_t *lfs, lfsr_file_t *file, lfs_off_t size_) {
}
// small files remain perpetually unflushed
file->o.o.flags |= LFS_O_UNFLUSH;
file->o.o.flags |= LFS_o_UNFLUSH;
lfsr_bshrub_init(&file->o.bshrub);
file->buffer.pos = 0;
file->buffer.size = size_;
@@ -12928,7 +12928,7 @@ int lfsr_file_fruncate(lfs_t *lfs, lfsr_file_t *file, lfs_off_t size_) {
// checkpoint the allocator
lfs_alloc_ckpoint(lfs);
// mark as unsynced in case we fail
file->o.o.flags |= LFS_O_UNSYNC;
file->o.o.flags |= LFS_o_UNSYNC;
// does our file become small?
if (size_ <= lfsr_file_inlinesize(lfs, file)) {
@@ -12976,7 +12976,7 @@ int lfsr_file_fruncate(lfs_t *lfs, lfsr_file_t *file, lfs_off_t size_) {
}
// small files remain perpetually unflushed
file->o.o.flags |= LFS_O_UNFLUSH;
file->o.o.flags |= LFS_o_UNFLUSH;
lfsr_bshrub_init(&file->o.bshrub);
file->buffer.pos = 0;
file->buffer.size = size_;
@@ -13201,7 +13201,7 @@ static int lfs_init(lfs_t *lfs, uint32_t flags,
// setup flags
lfs->flags = flags
// assume we contain orphans until proven otherwise
| LFS_I_UNTIDY
| LFS_i_UNTIDY
// default to an empty lookahead
| LFS_I_LOOKAHEAD
// default to assuming we need compaction somewhere, worst case
@@ -13420,16 +13420,16 @@ static int lfs_deinit(lfs_t *lfs) {
// note, "understanding" does not necessarily mean support
//
enum lfsr_rcompat {
LFSR_RCOMPAT_NONSTANDARD = 0x0001,
LFSR_RCOMPAT_MLEAF = 0x0002,
LFSR_RCOMPAT_MTREE = 0x0008,
LFSR_RCOMPAT_BSPROUT = 0x0010,
LFSR_RCOMPAT_BLEAF = 0x0020,
LFSR_RCOMPAT_BSHRUB = 0x0040,
LFSR_RCOMPAT_BTREE = 0x0080,
LFSR_RCOMPAT_GRM = 0x0100,
LFSR_RCOMPAT_NONSTANDARD = 0x0001, // Non-standard filesystem format
LFSR_RCOMPAT_MLEAF = 0x0002, // May use a single mdir pointer
LFSR_RCOMPAT_MTREE = 0x0008, // May use an mtree
LFSR_RCOMPAT_BSPROUT = 0x0010, // Files may use inlined data
LFSR_RCOMPAT_BLEAF = 0x0020, // Files may use single block pointers
LFSR_RCOMPAT_BSHRUB = 0x0040, // Files may use inlined btrees
LFSR_RCOMPAT_BTREE = 0x0080, // Files may use btrees
LFSR_RCOMPAT_GRM = 0x0100, // May use a global-remove
// internal
LFSR_RCOMPAT_OVERFLOW = 0x8000,
LFSR_rcompat_OVERFLOW = 0x8000, // Can't represent all flags
};
#define LFSR_RCOMPAT_COMPAT \
@@ -13442,17 +13442,17 @@ enum lfsr_rcompat {
| LFSR_RCOMPAT_GRM)
enum lfsr_wcompat {
LFSR_WCOMPAT_NONSTANDARD = 0x0001,
LFSR_WCOMPAT_NONSTANDARD = 0x0001, // Non-standard filesystem format
// internal
LFSR_WCOMPAT_OVERFLOW = 0x8000,
LFSR_wcompat_OVERFLOW = 0x8000, // Can't represent all flags
};
#define LFSR_WCOMPAT_COMPAT 0
enum lfsr_ocompat {
LFSR_OCOMPAT_NONSTANDARD = 0x0001,
LFSR_OCOMPAT_NONSTANDARD = 0x0001, // Non-standard filesystem format
// internal
LFSR_OCOMPAT_OVERFLOW = 0x8000,
LFSR_ocompat_OVERFLOW = 0x8000, // Can't represent all flags
};
#define LFSR_OCOMPAT_COMPAT 0
@@ -14192,7 +14192,7 @@ int lfsr_fs_stat(lfs_t *lfs, struct lfs_fsinfo *fsinfo) {
| LFS_IFDEF_CKFETCHES(LFS_I_CKFETCHES, 0)
| LFS_IFDEF_CKPARITY(LFS_I_CKPARITY, 0)
| LFS_IFDEF_CKDATACKSUMS(LFS_I_CKDATACKSUMS, 0)
| LFS_I_MKCONSISTENT // synonym for LFS_I_UNTIDY
| LFS_I_MKCONSISTENT // synonym for LFS_i_UNTIDY
| LFS_I_LOOKAHEAD
| LFS_I_COMPACT
| LFS_I_CKMETA
@@ -14451,7 +14451,7 @@ static int lfsr_fs_gc_(lfs_t *lfs, lfsr_traversal_t *t,
// do we have any pending work?
uint32_t pending = flags & (
(lfs->flags & (
LFS_I_UNTIDY
LFS_i_UNTIDY
| LFS_I_LOOKAHEAD
| LFS_I_COMPACT
| LFS_I_CKMETA
@@ -14505,7 +14505,7 @@ static int lfsr_fs_gc_(lfs_t *lfs, lfsr_traversal_t *t,
// clear any pending flags we make progress on
pending &= lfs->flags & (
LFS_I_UNTIDY
LFS_i_UNTIDY
| LFS_I_LOOKAHEAD
| LFS_I_COMPACT
| LFS_I_CKMETA
@@ -14772,7 +14772,7 @@ static int lfsr_traversal_rewind_(lfs_t *lfs, lfsr_traversal_t *t) {
// reset traversal
lfsr_traversal_init(t,
t->o.o.flags & ~(LFS_T_DIRTY | LFS_T_MUTATED | LFS_T_TSTATE));
t->o.o.flags & ~(LFS_t_DIRTY | LFS_t_MUTATED | LFS_t_TSTATE));
// and clear any pending blocks
t->blocks[0] = -1;
+14 -10
View File
@@ -126,6 +126,7 @@ enum lfs_type {
};
// File open flags
#define LFS_O_MODE 3 // The file's access mode
#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
@@ -140,11 +141,11 @@ enum lfs_type {
#define LFS_O_CKDATA 0x00020000 // Check metadata + data checksums
// internally used flags, don't use these
#define LFS_O_TYPE 0xff000000 // The file's type
#define LFS_O_UNFLUSH 0x00100000 // File's data does not match disk
#define LFS_O_UNSYNC 0x00200000 // File's metadata does not match disk
#define LFS_O_UNCREAT 0x00400000 // File does not exist yet
#define LFS_O_ZOMBIE 0x00800000 // File has been removed
#define LFS_o_TYPE 0xff000000 // The file's type
#define LFS_o_UNFLUSH 0x00100000 // File's data does not match disk
#define LFS_o_UNSYNC 0x00200000 // File's metadata does not match disk
#define LFS_o_UNCREAT 0x00400000 // File does not exist yet
#define LFS_o_ZOMBIE 0x00800000 // File has been removed
// File seek flags
#define LFS_SEEK_SET 0 // Seek relative to an absolute position
@@ -152,12 +153,14 @@ enum lfs_type {
#define LFS_SEEK_END 2 // Seek relative to the end of the file
// Custom attribute flags
#define LFS_A_MODE 3 // The attr's access mode
#define LFS_A_RDONLY 0 // Open an attr as read only
#define LFS_A_WRONLY 1 // Open an attr as write only
#define LFS_A_RDWR 2 // Open an attr as read and write
#define LFS_A_LAZY 0x04 // Only write attr if file changed
// Filesystem format flags
#define LFS_F_MODE 1 // Format's access mode
#define LFS_F_RDWR 0 // Format the filesystem as read and write
#ifdef LFS_CKPROGS
#define LFS_F_CKPROGS 0x00100000 // Check progs by reading back progged data
@@ -177,6 +180,7 @@ enum lfs_type {
#define LFS_F_CKDATA 0x00020000 // Check metadata + data checksums
// Filesystem mount flags
#define LFS_M_MODE 1 // Mount's access mode
#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_FLUSH 0x00000040 // Open all files with LFS_O_FLUSH
@@ -228,7 +232,7 @@ enum lfs_type {
#define LFS_I_CKDATA 0x00020000 // Data checksums not checked recently
// internally used flags, don't use these
#define LFS_I_UNTIDY 0x00001000 // Filesystem may have orphaned stickynotes
#define LFS_i_UNTIDY 0x00001000 // Filesystem may have orphaned stickynotes
// Block types
@@ -248,10 +252,10 @@ enum lfs_btype {
#define LFS_T_CKDATA 0x00020000 // Check metadata + data checksums
// internally used flags, don't use these
#define LFS_T_TSTATE 0x0000000f // The current traversal state
#define LFS_T_BTYPE 0x000000f0 // The current traversal btype
#define LFS_T_DIRTY 0x00000100 // Filesystem modified during traversal
#define LFS_T_MUTATED 0x00000200 // Filesystem modified by traversal
#define LFS_t_TSTATE 0x0000000f // The traversal's current tstate
#define LFS_t_BTYPE 0x000000f0 // The traversal's current btype
#define LFS_t_DIRTY 0x00000100 // Filesystem modified during traversal
#define LFS_t_MUTATED 0x00000200 // Filesystem modified by traversal
// GC flags
#define LFS_GC_MKCONSISTENT \
+24 -16
View File
@@ -31,35 +31,30 @@ def main(errs, *,
import builtins
list_, list = list, builtins.list
lines = []
# 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))
lines.append(('LFS_ERR_'+n, str(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:
if 'LFS_ERR_'+n == err.upper():
return n, e, h
# find by ERR_+name
for n, e, h in ERRS:
if 'ERR_'+n == err.upper():
return n, e, h
# find by name
for n, e, h in ERRS:
if n == err:
if n == err.upper():
return n, e, h
# find by E+name
for n, e, h in ERRS:
if 'E'+n == err:
if 'E'+n == err.upper():
return n, e, h
try:
# find by err code
@@ -78,9 +73,22 @@ def main(errs, *,
for err in errs:
try:
n, e, h = find_err(err)
print('%s %s %s' % ('LFS_ERR_'+n, e, h))
lines.append(('LFS_ERR_'+n, str(e), h))
except KeyError:
print('%s ?' % err)
lines.append(('?', err, '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__":
+313
View File
@@ -0,0 +1,313 @@
#!/usr/bin/env python3
# prevent local imports
if __name__ == "__main__":
__import__('sys').path.pop(0)
import collections as co
ALIASES = [
{'O', 'OPEN'},
{'A', 'ATTR'},
{'F', 'FORMAT'},
{'M', 'MOUNT'},
{'GC'},
{'I', 'INFO'},
{'T', 'TRAVERSAL'},
{'RC', 'RCOMPAT'},
{'WC', 'WCOMPAT'},
{'OC', 'OCOMPAT'}
]
FLAGS = [
# File open flags
('O', 'MODE', 3, "The file's access mode" ),
('^', 'RDONLY', 0, "Open a file as read only" ),
('^', 'WRONLY', 1, "Open a file as write only" ),
('^', 'RDWR', 2, "Open a file as read and write" ),
('O', 'CREAT', 0x00000004, "Create a file if it does not exist" ),
('O', 'EXCL', 0x00000008, "Fail if a file already exists" ),
('O', 'TRUNC', 0x00000010, "Truncate the existing file to zero size" ),
('O', 'APPEND', 0x00000020, "Move to end of file on every write" ),
('O', 'FLUSH', 0x00000040, "Flush data on every write" ),
('O', 'SYNC', 0x00000080, "Sync metadata on every write" ),
('O', 'DESYNC', 0x00000100, "Do not sync or recieve file updates" ),
('O', 'CKMETA', 0x00010000, "Check metadata checksums" ),
('O', 'CKDATA', 0x00020000, "Check metadata + data checksums" ),
('o', 'TYPE', 0xff000000, "The file's type" ),
('^', 'REG', 0x01000000, "Type = regular-file" ),
('^', 'DIR', 0x02000000, "Type = directory" ),
('^', 'BOOKMARK', 0x04000000, "Type = bookmark" ),
('^', 'STICKYNOTE',0x05000000, "Type = stickynote" ),
('^', 'TRAVERSAL', 0x09000000, "Type = traversal" ),
('o', 'UNFLUSH', 0x00100000, "File's data does not match disk" ),
('o', 'UNSYNC', 0x00200000, "File's metadata does not match disk" ),
('o', 'UNCREAT', 0x00400000, "File does not exist yet" ),
('o', 'ZOMBIE', 0x00800000, "File has been removed" ),
# Custom attribute flags
('A', 'MODE', 3, "The attr's access mode" ),
('^', 'RDONLY', 0, "Open an attr as read only" ),
('^', 'WRONLY', 1, "Open an attr as write only" ),
('^', 'RDWR', 2, "Open an attr as read and write" ),
('A', 'LAZY', 0x04, "Only write attr if file changed" ),
# Filesystem format flags
('F', 'MODE', 1, "Format's access mode" ),
('^', 'RDWR', 0, "Format the filesystem as read and write" ),
('F', 'CKPROGS', 0x00100000, "Check progs by reading back progged data" ),
('F', 'CKFETCHES', 0x00200000, "Check block checksums before first use" ),
('F', 'CKPARITY', 0x00400000, "Check metadata tag parity bits" ),
('F', 'CKDATACKSUMS',
0x08000000, "Check data checksums on reads" ),
('F', 'CKMETA', 0x00010000, "Check metadata checksums" ),
('F', 'CKDATA', 0x00020000, "Check metadata + data checksums" ),
# Filesystem mount flags
('M', 'MODE', 1, "Mount's access mode" ),
('^', 'RDWR', 0, "Mount the filesystem as read and write" ),
('^', 'RDONLY', 1, "Mount the filesystem as read only" ),
('M', 'FLUSH', 0x00000040, "Open all files with LFS_O_FLUSH" ),
('M', 'SYNC', 0x00000080, "Open all files with LFS_O_SYNC" ),
('M', 'CKPROGS', 0x00100000, "Check progs by reading back progged data" ),
('M', 'CKFETCHES', 0x00200000, "Check block checksums before first use" ),
('M', 'CKPARITY', 0x00400000, "Check metadata tag parity bits" ),
('M', 'CKDATACKSUMS',
0x08000000, "Check data checksums on reads" ),
('M', 'MKCONSISTENT',
0x00001000, "Make the filesystem consistent" ),
('M', 'LOOKAHEAD', 0x00002000, "Populate lookahead buffer" ),
('M', 'COMPACT', 0x00008000, "Compact metadata logs" ),
('M', 'CKMETA', 0x00010000, "Check metadata checksums" ),
('M', 'CKDATA', 0x00020000, "Check metadata + data checksums" ),
('m', 'UNTIDY', 0x00001000, "Filesystem may have orphaned stickynotes" ),
# GC flags
('GC', 'MKCONSISTENT',
0x00001000, "Make the filesystem consistent" ),
('GC', 'LOOKAHEAD',0x00002000, "Populate lookahead buffer" ),
('GC', 'COMPACT', 0x00008000, "Compact metadata logs" ),
('GC', 'CKMETA', 0x00010000, "Check metadata checksums" ),
('GC', 'CKDATA', 0x00020000, "Check metadata + data checksums" ),
# Filesystem info flags
('I', 'RDONLY', 0x00000001, "Mounted read only" ),
('I', 'FLUSH', 0x00000040, "Mounted with LFS_M_FLUSH" ),
('I', 'SYNC', 0x00000080, "Mounted with LFS_M_SYNC" ),
('I', 'CKPROGS', 0x00100000, "Mounted with LFS_M_CKPROGS" ),
('I', 'CKFETCHES', 0x00200000, "Mounted with LFS_M_CKFETCHES" ),
('I', 'CKPARITY', 0x00400000, "Mounted with LFS_M_CKPARITY" ),
('I', 'CKDATACKSUMS',
0x08000000, "Mounted with LFS_M_CKDATACKSUMS" ),
('I', 'MKCONSISTENT',
0x00001000, "Filesystem needs mkconsistent to write" ),
('I', 'LOOKAHEAD', 0x00002000, "Lookahead buffer is not full" ),
('I', 'COMPACT', 0x00008000, "Filesystem may have uncompacted metadata" ),
('I', 'CKMETA', 0x00010000, "Metadata checksums not checked recently" ),
('I', 'CKDATA', 0x00020000, "Data checksums not checked recently" ),
# Traversal flags
('T', 'MTREEONLY', 0x00000800, "Only traverse the mtree" ),
('T', 'MKCONSISTENT',
0x00001000, "Make the filesystem consistent" ),
('T', 'LOOKAHEAD', 0x00002000, "Populate lookahead buffer" ),
('T', 'COMPACT', 0x00008000, "Compact metadata logs" ),
('T', 'CKMETA', 0x00010000, "Check metadata checksums" ),
('T', 'CKDATA', 0x00020000, "Check metadata + data checksums" ),
('t', 'TSTATE', 0x0000000f, "The traversal's current tstate" ),
('^', 'MROOTANCHOR',
0x00000000, "Tstate = mroot-anchor" ),
('^', 'MROOTCHAIN',0x00000001, "Tstate = mroot-chain" ),
('^', 'MTREE', 0x00000002, "Tstate = mtree" ),
('^', 'MDIRS', 0x00000003, "Tstate = mtree-mdirs" ),
('^', 'MDIR', 0x00000004, "Tstate = mdir" ),
('^', 'BTREE', 0x00000005, "Tstate = btree" ),
('^', 'OMDIRS', 0x00000006, "Tstate = open-mdirs" ),
('^', 'OBTREE', 0x00000007, "Tstate = open-btree" ),
('^', 'DONE', 0x00000008, "Tstate = done" ),
('t', 'BTYPE', 0x000000f0, "The traversal's current btype" ),
('^', 'MDIR', 0x00000010, "Btype = mdir" ),
('^', 'BTREE', 0x00000020, "Btype = btree" ),
('^', 'DATA', 0x00000030, "Btype = data" ),
('t', 'DIRTY', 0x00000100, "Filesystem modified during traversal" ),
('t', 'MUTATED', 0x00000200, "Filesystem modified by traversal" ),
# Read-compat flags
('RCOMPAT', 'NONSTANDARD',
0x0001, "Non-standard filesystem format" ),
('RCOMPAT', 'MLEAF', 0x0002, "May use a single mdir pointer" ),
('RCOMPAT', 'MTREE', 0x0008, "May use an mdir btree" ),
('RCOMPAT', 'BSPROUT', 0x0010, "Files may use inlined data" ),
('RCOMPAT', 'BLEAF', 0x0020, "Files may use single block pointers" ),
('RCOMPAT', 'BSHRUB', 0x0040, "Files may use inlined btrees" ),
('RCOMPAT', 'BTREE', 0x0080, "Files may use btrees" ),
('RCOMPAT', 'GRM', 0x0100, "May use a global-remove" ),
('rcompat', 'OVERFLOW',0x8000, "Can't represent all flags" ),
# Write-compat flags
('WCOMPAT', 'NONSTANDARD',
0x0001, "Non-standard filesystem format" ),
('wcompat', 'OVERFLOW',0x8000, "Can't represent all flags" ),
# Optional-compat flags
('OCOMPAT', 'NONSTANDARD',
0x0001, "Non-standard filesystem format" ),
('ocompat', 'OVERFLOW',0x8000, "Can't represent all flags" ),
]
def main(flags, *,
list=False,
all=False):
import builtins
list_, list = list, builtins.list
all_, all = all, builtins.all
# first compile prefixes
prefixes = {}
for a in ALIASES:
for k in a:
prefixes[k] = a
for p, n, f, h in FLAGS:
if p not in prefixes:
prefixes[p] = {p}
# only look at specific prefix?
flags_ = []
prefix = set()
for f in flags:
if f.upper() in prefixes:
prefix.update(prefixes[f.upper()])
else:
flags_.append(f)
# filter by prefix
flags__ = []
types__ = co.defaultdict(lambda: set())
for p, n, f, h in FLAGS:
if p == '^':
p = last_p
t = last_t
types__[p].add(t)
else:
t = None
last_p = p
last_t = f
if not prefix or p.upper() in prefix:
flags__.append((p, t, n, f, h))
lines = []
# list all known flags
if list_:
for p, t, n, f, h in flags__:
if not all_ and (t is not None or p[0].islower()):
continue
lines.append(('LFS_%s_%s' % (p, n), '0x%08x' % f, h))
# find flags by name or value
else:
for f_ in flags_:
found = False
# find by LFS_+prefix+_+name
for p, t, n, f, h in flags__:
if 'LFS_%s_%s' % (p, n) == f_.upper():
lines.append(('LFS_%s_%s' % (p, n), '0x%08x' % f, h))
found = True
if found:
continue
# find by prefix+_+name
for p, t, n, f, h in flags__:
if '%s_%s' % (p, n) == f_.upper():
lines.append(('LFS_%s_%s' % (p, n), '0x%08x' % f, h))
found = True
if found:
continue
# find by name
for p, t, n, f, h in flags__:
if n == f_.upper():
lines.append(('LFS_%s_%s' % (p, n), '0x%08x' % f, h))
found = True
if found:
continue
# find by value
try:
f__ = int(f_, 0)
f___ = f__
for p, t, n, f, h in flags__:
# ignore type masks here
if t is None and f in types__[p]:
continue
# matches flag?
if t is None and (f__ & f) == f:
lines.append(('LFS_%s_%s' % (p, n), '0x%08x' % f, h))
f___ &= ~f
# matches type?
elif t is not None and (f__ & t) == f:
lines.append(('LFS_%s_%s' % (p, n), '0x%08x' % f, h))
f___ &= ~t
if f___:
lines.append(('?', '0x%08x' % f___, 'Unknown flags'))
except ValueError:
lines.append(('?', f_, 'Unknown flag'))
# 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)
class AppendFlags(argparse.Action):
def __call__(self, parser, namespace, value, option):
if getattr(namespace, 'flags', None) is None:
namespace.flags = []
if value is None:
pass
elif isinstance(value, str):
namespace.flags.append(value)
else:
namespace.flags.extend(value)
parser.add_argument(
'prefix',
nargs='?',
action=AppendFlags,
help="Flag prefix to consider, defaults to all flags.")
parser.add_argument(
'flags',
nargs='*',
action=AppendFlags,
help="Flags or names of flags to decode.")
parser.add_argument(
'-l', '--list',
action='store_true',
help="List all known flags.")
parser.add_argument(
'-a', '--all',
action='store_true',
help="Also show internal flags and types.")
sys.exit(main(**{k: v
for k, v in vars(parser.parse_intermixed_args()).items()
if v is not None}))
+4 -4
View File
@@ -5314,7 +5314,7 @@ code = '''
// we should have cleaned up all grms/orphans
assert(lfs.grm.mids[0] == -1);
assert(lfs.grm.mids[1] == -1);
assert(!(lfs.flags & LFS_I_UNTIDY));
assert(!(lfs.flags & LFS_i_UNTIDY));
struct lfs_fsinfo fsinfo;
lfsr_fs_stat(&lfs, &fsinfo) => 0;
@@ -5450,7 +5450,7 @@ code = '''
// we should have cleaned up all grms/orphans
assert(lfs.grm.mids[0] == -1);
assert(lfs.grm.mids[1] == -1);
assert(!(lfs.flags & LFS_I_UNTIDY));
assert(!(lfs.flags & LFS_i_UNTIDY));
struct lfs_fsinfo fsinfo;
lfsr_fs_stat(&lfs, &fsinfo) => 0;
@@ -5600,7 +5600,7 @@ code = '''
// we should have cleaned up all grms/orphans
assert(lfs.grm.mids[0] == -1);
assert(lfs.grm.mids[1] == -1);
assert(!(lfs.flags & LFS_I_UNTIDY));
assert(!(lfs.flags & LFS_i_UNTIDY));
struct lfs_fsinfo fsinfo;
lfsr_fs_stat(&lfs, &fsinfo) => 0;
@@ -5756,7 +5756,7 @@ code = '''
// we should have cleaned up all grms/orphans
assert(lfs.grm.mids[0] == -1);
assert(lfs.grm.mids[1] == -1);
assert(!(lfs.flags & LFS_I_UNTIDY));
assert(!(lfs.flags & LFS_i_UNTIDY));
struct lfs_fsinfo fsinfo;
lfsr_fs_stat(&lfs, &fsinfo) => 0;
+8 -8
View File
@@ -6458,7 +6458,7 @@ code = '''
// we should have cleaned up all grms/orphans
assert(lfs.grm.mids[0] == -1);
assert(lfs.grm.mids[1] == -1);
assert(!(lfs.flags & LFS_I_UNTIDY));
assert(!(lfs.flags & LFS_i_UNTIDY));
// which means there shouldn't be that many files left
assert((lfs.mtree.u.weight & 0x7fffffff) <= (2 << lfs.mdir_bits));
@@ -6602,7 +6602,7 @@ code = '''
assert(lfs.grm.mids[1] == -1);
// if we introduce actual orphans, me _must not_ clear the orphan flag
if (ORPHANS >= 3) {
assert(lfs.flags & LFS_I_UNTIDY);
assert(lfs.flags & LFS_i_UNTIDY);
}
// if we introduced actual orphans, we _must_ be marked as inconsistent
@@ -6759,7 +6759,7 @@ code = '''
// we should have cleaned up all grms/orphans
assert(lfs.grm.mids[0] == -1);
assert(lfs.grm.mids[1] == -1);
assert(!(lfs.flags & LFS_I_UNTIDY));
assert(!(lfs.flags & LFS_i_UNTIDY));
// which means there shouldn't be that many files left
assert((lfs.mtree.u.weight & 0x7fffffff) <= (2 << lfs.mdir_bits));
@@ -6917,7 +6917,7 @@ code = '''
// we should have cleaned up all grms/orphans
assert(lfs.grm.mids[0] == -1);
assert(lfs.grm.mids[1] == -1);
assert(!(lfs.flags & LFS_I_UNTIDY));
assert(!(lfs.flags & LFS_i_UNTIDY));
// which means there shouldn't be that many files left
assert((lfs.mtree.u.weight & 0x7fffffff) <= (2 << lfs.mdir_bits));
@@ -7086,7 +7086,7 @@ code = '''
// we should have cleaned up all grms/orphans
assert(lfs.grm.mids[0] == -1);
assert(lfs.grm.mids[1] == -1);
assert(!(lfs.flags & LFS_I_UNTIDY));
assert(!(lfs.flags & LFS_i_UNTIDY));
// which means there shouldn't be that many files left
assert((lfs.mtree.u.weight & 0x7fffffff) <= (2 << lfs.mdir_bits));
@@ -7253,7 +7253,7 @@ code = '''
// we should have cleaned up all grms/orphans
assert(lfs.grm.mids[0] == -1);
assert(lfs.grm.mids[1] == -1);
assert(!(lfs.flags & LFS_I_UNTIDY));
assert(!(lfs.flags & LFS_i_UNTIDY));
// which means there shouldn't be that many files left
assert((lfs.mtree.u.weight & 0x7fffffff) <= (2 << lfs.mdir_bits));
@@ -7418,7 +7418,7 @@ code = '''
// we should have cleaned up all grms/orphans
assert(lfs.grm.mids[0] == -1);
assert(lfs.grm.mids[1] == -1);
assert(!(lfs.flags & LFS_I_UNTIDY));
assert(!(lfs.flags & LFS_i_UNTIDY));
// which means there shouldn't be that many files left
assert((lfs.mtree.u.weight & 0x7fffffff) <= (2 << lfs.mdir_bits));
@@ -7613,7 +7613,7 @@ code = '''
assert(lfs.grm.mids[1] == -1);
// if we introduce actual orphans, me _must not_ clear the orphan flag
if (ORPHANS >= 3) {
assert(lfs.flags & LFS_I_UNTIDY);
assert(lfs.flags & LFS_i_UNTIDY);
}
// mdirs should have been compacted