From a5747bb2b2d800a22aa209c834a7d26aba48d269 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sat, 12 Apr 2025 17:45:26 -0500 Subject: [PATCH] scripts: dbgmtree.py: Fixed minor mtree rendering/traversal issues - Added TreeArt __bool__ and __len__. This was causing a crash in _treeartfrommtreertree when rtree was empty. The code was not updated in the set -> TreeArt class transition, and went unnoticed because it's unlikely to be hit unless the filesystem is corrupt. Fortunately(?) realtime rendering creates a bunch of transiently corrupt filesystem images. - Tweaked lookupleaf to not include mroots in their own paths. This matches the behavior of leaf mdirs, and is intentionally different from btree's lookupleaf which needs to lookup the leaf rattr to terminate. - Tweaked leaves to not remove the last path entry if it is an mdir. This hid the previous lookupleaf inconsistency. We only remove the last rbyd from the path because it is redundant, and for mdirs/mroots it should never be redundant. I ended up just replacing the corrupt check with an explicit check that the rbyd is redundant. This should be more precise and avoid issues like this in the future. Also adopted explicit redundant checks in Btree.leaves and Lfs.File.leaves. --- scripts/dbgbmap.py | 29 ++++++++++++++++++++--------- scripts/dbgbmapd3.py | 29 ++++++++++++++++++++--------- scripts/dbgbtree.py | 10 +++++++++- scripts/dbglfs.py | 37 +++++++++++++++++++++++++++---------- scripts/dbgmtree.py | 31 +++++++++++++++++++++++-------- scripts/dbgrbyd.py | 9 +++++++++ 6 files changed, 108 insertions(+), 37 deletions(-) diff --git a/scripts/dbgbmap.py b/scripts/dbgbmap.py index ef829a8e..2c0a6ea4 100755 --- a/scripts/dbgbmap.py +++ b/scripts/dbgbmap.py @@ -1203,7 +1203,9 @@ class Btree: if path: yield (bid-rid + (rbyd.weight-1), rbyd, # path tail is usually redundant unless corrupt - path_[:-1] if rbyd else path_) + path_[:-1] + if path_ and path_[-1][1] == rbyd + else path_) else: yield bid-rid + (rbyd.weight-1), rbyd bid += rbyd.weight - rid + 1 @@ -1754,8 +1756,6 @@ class Mtree: # iterate over mrootchain path_ = [] for mroot in self.mrootchain: - name = mroot.lookup(-1, TAG_MAGIC) - path_.append((mroot.mid, mroot, name)) # stop here? if depth and len(path_) >= depth: if path: @@ -1763,6 +1763,9 @@ class Mtree: else: return mroot + name = mroot.lookup(-1, TAG_MAGIC) + path_.append((mroot.mid, mroot, name)) + # no mtree? must be inlined in mroot if self.mtree is None: if mid.mbid >= (1 << self.mbits): @@ -1903,12 +1906,13 @@ class Mtree: yield mroot if path or depth: - name = mroot.lookup(-1, TAG_MAGIC) - path_.append((mroot.mid, mroot, name)) # stop here? if depth and len(path_) >= depth: return + name = mroot.lookup(-1, TAG_MAGIC) + path_.append((mroot.mid, mroot, name)) + # do we even have an mtree? if self.mtree is not None: # include the mtree root even if the weight is zero @@ -1945,7 +1949,11 @@ class Mtree: if path: yield ((bid-rid + (rbyd.weight-1), rbyd), # path tail is usually redundant unless corrupt - path_[:-1] if rbyd else path_) + path_[:-1] + if path_ + and isinstance(path_[-1][1], Rbyd) + and path_[-1][1] == rbyd + else path_) else: yield (bid-rid + (rbyd.weight-1), rbyd) mid = self.mid(bid-rid + (rbyd.weight-1) + 1) @@ -2128,8 +2136,6 @@ class Mtree: # iterate over mrootchain path_ = [] for mroot in self.mrootchain: - name = mroot.lookup(-1, TAG_MAGIC) - path_.append((mroot.mid, mroot, name)) # stop here? if depth and len(path_) >= depth: if path: @@ -2137,6 +2143,9 @@ class Mtree: else: return mroot + name = mroot.lookup(-1, TAG_MAGIC) + path_.append((mroot.mid, mroot, name)) + # no mtree? must be inlined in mroot if self.mtree is None: mdir = Mdir(0, self.mroot) @@ -3423,7 +3432,9 @@ class Lfs: if path: yield (pos, rbyd, # path tail is usually redundant unless corrupt - path_[:-1] if rbyd else path_) + path_[:-1] + if path_ and path_[-1][1] == rbyd + else path_) else: yield pos, rbyd pos += rbyd.weight diff --git a/scripts/dbgbmapd3.py b/scripts/dbgbmapd3.py index 63e89acb..714c1bf0 100755 --- a/scripts/dbgbmapd3.py +++ b/scripts/dbgbmapd3.py @@ -1233,7 +1233,9 @@ class Btree: if path: yield (bid-rid + (rbyd.weight-1), rbyd, # path tail is usually redundant unless corrupt - path_[:-1] if rbyd else path_) + path_[:-1] + if path_ and path_[-1][1] == rbyd + else path_) else: yield bid-rid + (rbyd.weight-1), rbyd bid += rbyd.weight - rid + 1 @@ -1784,8 +1786,6 @@ class Mtree: # iterate over mrootchain path_ = [] for mroot in self.mrootchain: - name = mroot.lookup(-1, TAG_MAGIC) - path_.append((mroot.mid, mroot, name)) # stop here? if depth and len(path_) >= depth: if path: @@ -1793,6 +1793,9 @@ class Mtree: else: return mroot + name = mroot.lookup(-1, TAG_MAGIC) + path_.append((mroot.mid, mroot, name)) + # no mtree? must be inlined in mroot if self.mtree is None: if mid.mbid >= (1 << self.mbits): @@ -1933,12 +1936,13 @@ class Mtree: yield mroot if path or depth: - name = mroot.lookup(-1, TAG_MAGIC) - path_.append((mroot.mid, mroot, name)) # stop here? if depth and len(path_) >= depth: return + name = mroot.lookup(-1, TAG_MAGIC) + path_.append((mroot.mid, mroot, name)) + # do we even have an mtree? if self.mtree is not None: # include the mtree root even if the weight is zero @@ -1975,7 +1979,11 @@ class Mtree: if path: yield ((bid-rid + (rbyd.weight-1), rbyd), # path tail is usually redundant unless corrupt - path_[:-1] if rbyd else path_) + path_[:-1] + if path_ + and isinstance(path_[-1][1], Rbyd) + and path_[-1][1] == rbyd + else path_) else: yield (bid-rid + (rbyd.weight-1), rbyd) mid = self.mid(bid-rid + (rbyd.weight-1) + 1) @@ -2158,8 +2166,6 @@ class Mtree: # iterate over mrootchain path_ = [] for mroot in self.mrootchain: - name = mroot.lookup(-1, TAG_MAGIC) - path_.append((mroot.mid, mroot, name)) # stop here? if depth and len(path_) >= depth: if path: @@ -2167,6 +2173,9 @@ class Mtree: else: return mroot + name = mroot.lookup(-1, TAG_MAGIC) + path_.append((mroot.mid, mroot, name)) + # no mtree? must be inlined in mroot if self.mtree is None: mdir = Mdir(0, self.mroot) @@ -3453,7 +3462,9 @@ class Lfs: if path: yield (pos, rbyd, # path tail is usually redundant unless corrupt - path_[:-1] if rbyd else path_) + path_[:-1] + if path_ and path_[-1][1] == rbyd + else path_) else: yield pos, rbyd pos += rbyd.weight diff --git a/scripts/dbgbtree.py b/scripts/dbgbtree.py index 22d2bd3d..1692c6a4 100755 --- a/scripts/dbgbtree.py +++ b/scripts/dbgbtree.py @@ -1111,7 +1111,9 @@ class Btree: if path: yield (bid-rid + (rbyd.weight-1), rbyd, # path tail is usually redundant unless corrupt - path_[:-1] if rbyd else path_) + path_[:-1] + if path_ and path_[-1][1] == rbyd + else path_) else: yield bid-rid + (rbyd.weight-1), rbyd bid += rbyd.weight - rid + 1 @@ -1352,6 +1354,12 @@ class TreeArt: def __iter__(self): return iter(self.tree) + def __bool__(self): + return bool(self.tree) + + def __len__(self): + return len(self.tree) + # render an rbyd rbyd tree for debugging @classmethod def _fromrbydrtree(cls, rbyd, **args): diff --git a/scripts/dbglfs.py b/scripts/dbglfs.py index 0c5308a2..557eaedb 100755 --- a/scripts/dbglfs.py +++ b/scripts/dbglfs.py @@ -1160,7 +1160,9 @@ class Btree: if path: yield (bid-rid + (rbyd.weight-1), rbyd, # path tail is usually redundant unless corrupt - path_[:-1] if rbyd else path_) + path_[:-1] + if path_ and path_[-1][1] == rbyd + else path_) else: yield bid-rid + (rbyd.weight-1), rbyd bid += rbyd.weight - rid + 1 @@ -1711,8 +1713,6 @@ class Mtree: # iterate over mrootchain path_ = [] for mroot in self.mrootchain: - name = mroot.lookup(-1, TAG_MAGIC) - path_.append((mroot.mid, mroot, name)) # stop here? if depth and len(path_) >= depth: if path: @@ -1720,6 +1720,9 @@ class Mtree: else: return mroot + name = mroot.lookup(-1, TAG_MAGIC) + path_.append((mroot.mid, mroot, name)) + # no mtree? must be inlined in mroot if self.mtree is None: if mid.mbid >= (1 << self.mbits): @@ -1860,12 +1863,13 @@ class Mtree: yield mroot if path or depth: - name = mroot.lookup(-1, TAG_MAGIC) - path_.append((mroot.mid, mroot, name)) # stop here? if depth and len(path_) >= depth: return + name = mroot.lookup(-1, TAG_MAGIC) + path_.append((mroot.mid, mroot, name)) + # do we even have an mtree? if self.mtree is not None: # include the mtree root even if the weight is zero @@ -1902,7 +1906,11 @@ class Mtree: if path: yield ((bid-rid + (rbyd.weight-1), rbyd), # path tail is usually redundant unless corrupt - path_[:-1] if rbyd else path_) + path_[:-1] + if path_ + and isinstance(path_[-1][1], Rbyd) + and path_[-1][1] == rbyd + else path_) else: yield (bid-rid + (rbyd.weight-1), rbyd) mid = self.mid(bid-rid + (rbyd.weight-1) + 1) @@ -2085,8 +2093,6 @@ class Mtree: # iterate over mrootchain path_ = [] for mroot in self.mrootchain: - name = mroot.lookup(-1, TAG_MAGIC) - path_.append((mroot.mid, mroot, name)) # stop here? if depth and len(path_) >= depth: if path: @@ -2094,6 +2100,9 @@ class Mtree: else: return mroot + name = mroot.lookup(-1, TAG_MAGIC) + path_.append((mroot.mid, mroot, name)) + # no mtree? must be inlined in mroot if self.mtree is None: mdir = Mdir(0, self.mroot) @@ -3380,7 +3389,9 @@ class Lfs: if path: yield (pos, rbyd, # path tail is usually redundant unless corrupt - path_[:-1] if rbyd else path_) + path_[:-1] + if path_ and path_[-1][1] == rbyd + else path_) else: yield pos, rbyd pos += rbyd.weight @@ -3648,6 +3659,12 @@ class TreeArt: def __iter__(self): return iter(self.tree) + def __bool__(self): + return bool(self.tree) + + def __len__(self): + return len(self.tree) + # render an rbyd rbyd tree for debugging @classmethod def _fromrbydrtree(cls, rbyd, **args): @@ -3808,7 +3825,7 @@ class TreeArt: return '%s ' % ''.join(trunk) - # some more renderers +# some more renderers # render a btree rbyd tree for debugging @classmethod diff --git a/scripts/dbgmtree.py b/scripts/dbgmtree.py index 41182441..35f0e685 100755 --- a/scripts/dbgmtree.py +++ b/scripts/dbgmtree.py @@ -1126,7 +1126,9 @@ class Btree: if path: yield (bid-rid + (rbyd.weight-1), rbyd, # path tail is usually redundant unless corrupt - path_[:-1] if rbyd else path_) + path_[:-1] + if path_ and path_[-1][1] == rbyd + else path_) else: yield bid-rid + (rbyd.weight-1), rbyd bid += rbyd.weight - rid + 1 @@ -1677,8 +1679,6 @@ class Mtree: # iterate over mrootchain path_ = [] for mroot in self.mrootchain: - name = mroot.lookup(-1, TAG_MAGIC) - path_.append((mroot.mid, mroot, name)) # stop here? if depth and len(path_) >= depth: if path: @@ -1686,6 +1686,9 @@ class Mtree: else: return mroot + name = mroot.lookup(-1, TAG_MAGIC) + path_.append((mroot.mid, mroot, name)) + # no mtree? must be inlined in mroot if self.mtree is None: if mid.mbid >= (1 << self.mbits): @@ -1826,12 +1829,13 @@ class Mtree: yield mroot if path or depth: - name = mroot.lookup(-1, TAG_MAGIC) - path_.append((mroot.mid, mroot, name)) # stop here? if depth and len(path_) >= depth: return + name = mroot.lookup(-1, TAG_MAGIC) + path_.append((mroot.mid, mroot, name)) + # do we even have an mtree? if self.mtree is not None: # include the mtree root even if the weight is zero @@ -1868,7 +1872,11 @@ class Mtree: if path: yield ((bid-rid + (rbyd.weight-1), rbyd), # path tail is usually redundant unless corrupt - path_[:-1] if rbyd else path_) + path_[:-1] + if path_ + and isinstance(path_[-1][1], Rbyd) + and path_[-1][1] == rbyd + else path_) else: yield (bid-rid + (rbyd.weight-1), rbyd) mid = self.mid(bid-rid + (rbyd.weight-1) + 1) @@ -2051,8 +2059,6 @@ class Mtree: # iterate over mrootchain path_ = [] for mroot in self.mrootchain: - name = mroot.lookup(-1, TAG_MAGIC) - path_.append((mroot.mid, mroot, name)) # stop here? if depth and len(path_) >= depth: if path: @@ -2060,6 +2066,9 @@ class Mtree: else: return mroot + name = mroot.lookup(-1, TAG_MAGIC) + path_.append((mroot.mid, mroot, name)) + # no mtree? must be inlined in mroot if self.mtree is None: mdir = Mdir(0, self.mroot) @@ -2247,6 +2256,12 @@ class TreeArt: def __iter__(self): return iter(self.tree) + def __bool__(self): + return bool(self.tree) + + def __len__(self): + return len(self.tree) + # render an rbyd rbyd tree for debugging @classmethod def _fromrbydrtree(cls, rbyd, **args): diff --git a/scripts/dbgrbyd.py b/scripts/dbgrbyd.py index b5deafb4..439d43dc 100755 --- a/scripts/dbgrbyd.py +++ b/scripts/dbgrbyd.py @@ -1299,6 +1299,15 @@ class TreeArt: else: self.width = 0 + def __iter__(self): + return iter(self.tree) + + def __bool__(self): + return bool(self.tree) + + def __len__(self): + return len(self.tree) + # render an rbyd rbyd tree for debugging @classmethod def _fromrbydrtree(cls, rbyd, **args):