summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/btrfs/btrfstree/btree.go14
-rw-r--r--lib/btrfs/btrfstree/btree_tree.go82
-rw-r--r--lib/btrfs/btrfstree/path.go47
-rw-r--r--lib/btrfs/io3_btree.go2
-rw-r--r--lib/btrfsutil/old_rebuilt_forrest.go79
-rw-r--r--lib/btrfsutil/rebuilt_forrest.go2
-rw-r--r--lib/containers/arcache.go9
7 files changed, 104 insertions, 131 deletions
diff --git a/lib/btrfs/btrfstree/btree.go b/lib/btrfs/btrfstree/btree.go
index 25259c0..e7be281 100644
--- a/lib/btrfs/btrfstree/btree.go
+++ b/lib/btrfs/btrfstree/btree.go
@@ -21,6 +21,11 @@ type Forrest interface {
}
type Tree interface {
+ // TreeParentID returns the ID of this tree's parent and the
+ // generation that this tree was split from its parent. If
+ // this tree has no parent, then (0, 0, nil) is returned.
+ TreeParentID(ctx context.Context) (btrfsprim.ObjID, btrfsprim.Generation, error)
+
// TreeLookup looks up the Item for a given key.
//
// If no such Item exists, but there is otherwise no error,
@@ -70,15 +75,6 @@ type Tree interface {
handleFn func(Item) bool,
) error
- // CheckOwner returns whether it is permissible for a node
- // with .Head.Owner=owner and .Head.Generation=gen to be in
- // this tree.
- //
- // If there is an error determining this, then `failOpen`
- // specifies whether it should return an error (false) or nil
- // (true).
- TreeCheckOwner(ctx context.Context, failOpen bool, owner btrfsprim.ObjID, gen btrfsprim.Generation) error
-
// TreeWalk is a lower-level call than TreeSubrange. Use with
// hesitancy.
//
diff --git a/lib/btrfs/btrfstree/btree_tree.go b/lib/btrfs/btrfstree/btree_tree.go
index 7cfa257..6056ae8 100644
--- a/lib/btrfs/btrfstree/btree_tree.go
+++ b/lib/btrfs/btrfstree/btree_tree.go
@@ -38,7 +38,7 @@ func (tree *RawTree) TreeWalk(ctx context.Context, cbs TreeWalkHandler) {
}
path := Path{
PathRoot{
- Tree: tree,
+ Forrest: tree.Forrest,
TreeID: tree.ID,
ToAddr: tree.RootNode,
ToGeneration: tree.Generation,
@@ -317,63 +317,27 @@ func (tree *RawTree) TreeSubrange(ctx context.Context, min int, searcher TreeSea
return nil
}
-// TreeCheckOwner implements the 'Tree' interface.
-func (tree *RawTree) TreeCheckOwner(ctx context.Context, failOpen bool, owner btrfsprim.ObjID, gen btrfsprim.Generation) error {
- var uuidTree *RawTree
- for {
- // Main.
- if owner == tree.ID {
- return nil
- }
- if tree.ParentUUID == (btrfsprim.UUID{}) {
- return fmt.Errorf("owner=%v is not acceptable in this tree",
- owner)
- }
- if gen > tree.ParentGen {
- return fmt.Errorf("claimed owner=%v might be acceptable in this tree (if generation<=%v) but not with claimed generation=%v",
- owner, tree.ParentGen, gen)
- }
-
- // Loop update.
- if uuidTree == nil {
- var err error
- uuidTree, err = tree.Forrest.RawTree(ctx, btrfsprim.UUID_TREE_OBJECTID)
- if err != nil {
- if failOpen {
- return nil
- }
- return fmt.Errorf("unable to determine whether owner=%v generation=%v is acceptable: %w",
- owner, gen, err)
- }
- }
- parentIDItem, err := uuidTree.TreeLookup(ctx, btrfsitem.UUIDToKey(tree.ParentUUID))
- if err != nil {
- if failOpen {
- return nil
- }
- return fmt.Errorf("unable to determine whether owner=%v generation=%v is acceptable: %w",
- owner, gen, err)
- }
- switch parentIDBody := parentIDItem.Body.(type) {
- case *btrfsitem.UUIDMap:
- tree, err = tree.Forrest.RawTree(ctx, parentIDBody.ObjID)
- if err != nil {
- if failOpen {
- return nil
- }
- return fmt.Errorf("unable to determine whether owner=%v generation=%v is acceptable: %w",
- owner, gen, err)
- }
- case *btrfsitem.Error:
- if failOpen {
- return nil
- }
- return fmt.Errorf("unable to determine whether owner=%v generation=%v is acceptable: %w",
- owner, gen, parentIDBody.Err)
- default:
- // This is a panic because the item decoder should not emit UUID_SUBVOL items as anything but
- // btrfsitem.UUIDMap or btrfsitem.Error without this code also being updated.
- panic(fmt.Errorf("should not happen: UUID_SUBVOL item has unexpected type: %T", parentIDBody))
- }
+// TreeParentID implements the 'Tree' interface.
+func (tree *RawTree) TreeParentID(ctx context.Context) (btrfsprim.ObjID, btrfsprim.Generation, error) {
+ if tree.ParentUUID == (btrfsprim.UUID{}) {
+ return 0, 0, nil
+ }
+ uuidTree, err := tree.Forrest.RawTree(ctx, btrfsprim.UUID_TREE_OBJECTID)
+ if err != nil {
+ return 0, 0, err
+ }
+ parentIDItem, err := uuidTree.TreeLookup(ctx, btrfsitem.UUIDToKey(tree.ParentUUID))
+ if err != nil {
+ return 0, 0, err
+ }
+ switch parentIDBody := parentIDItem.Body.(type) {
+ case *btrfsitem.UUIDMap:
+ return parentIDBody.ObjID, tree.ParentGen, nil
+ case *btrfsitem.Error:
+ return 0, 0, parentIDBody.Err
+ default:
+ // This is a panic because the item decoder should not emit UUID_SUBVOL items as anything but
+ // btrfsitem.UUIDMap or btrfsitem.Error without this code also being updated.
+ panic(fmt.Errorf("should not happen: UUID_SUBVOL item has unexpected type: %T", parentIDBody))
}
}
diff --git a/lib/btrfs/btrfstree/path.go b/lib/btrfs/btrfstree/path.go
index 537df9a..57669ee 100644
--- a/lib/btrfs/btrfstree/path.go
+++ b/lib/btrfs/btrfstree/path.go
@@ -69,7 +69,7 @@ type PathElem interface {
}
type PathRoot struct {
- Tree Tree
+ Forrest Forrest
// It should be no surprise that these 4 members mimic the 4
// members of a 'RawTree'.
TreeID btrfsprim.ObjID
@@ -133,6 +133,45 @@ func (path Path) String() string {
return ret.String()
}
+func checkOwner(
+ ctx context.Context, forrest Forrest, treeID btrfsprim.ObjID, failOpen bool,
+ ownerToCheck btrfsprim.ObjID, genToCheck btrfsprim.Generation,
+) error {
+ for {
+ if ownerToCheck == treeID {
+ return nil
+ }
+
+ tree, err := forrest.ForrestLookup(ctx, treeID)
+ if err != nil {
+ if failOpen {
+ return nil
+ }
+ return fmt.Errorf("unable to determine whether owner=%v generation=%v is acceptable: %w",
+ ownerToCheck, genToCheck, err)
+ }
+
+ parentID, parentGen, err := tree.TreeParentID(ctx)
+ if err != nil {
+ if failOpen {
+ return nil
+ }
+ return fmt.Errorf("unable to determine whether owner=%v generation=%v is acceptable: %w",
+ ownerToCheck, genToCheck, err)
+ }
+
+ if parentID == 0 && parentGen == 0 {
+ return fmt.Errorf("owner=%v is not acceptable in this tree",
+ ownerToCheck)
+ }
+ if genToCheck > parentGen {
+ return fmt.Errorf("claimed owner=%v might be acceptable in this tree (if generation<=%v) but not with claimed generation=%v",
+ ownerToCheck, parentGen, genToCheck)
+ }
+ treeID = parentID
+ }
+}
+
// NodeExpectations returns the address to read and the expectations
// to have when reading the node pointed to by this Path.
//
@@ -153,7 +192,8 @@ func (path Path) NodeExpectations(ctx context.Context, failOpen bool) (_ btrfsvo
Level: containers.OptionalValue(lastElem.ToLevel),
Generation: containers.OptionalValue(lastElem.ToGeneration),
Owner: func(owner btrfsprim.ObjID, gen btrfsprim.Generation) error {
- return firstElem.Tree.TreeCheckOwner(ctx, failOpen, owner, gen)
+ return checkOwner(ctx, firstElem.Forrest, lastElem.TreeID, failOpen,
+ owner, gen)
},
MinItem: containers.OptionalValue(btrfsprim.Key{}),
MaxItem: containers.OptionalValue(btrfsprim.MaxKey),
@@ -164,7 +204,8 @@ func (path Path) NodeExpectations(ctx context.Context, failOpen bool) (_ btrfsvo
Level: containers.OptionalValue(lastElem.ToLevel),
Generation: containers.OptionalValue(lastElem.ToGeneration),
Owner: func(owner btrfsprim.ObjID, gen btrfsprim.Generation) error {
- return firstElem.Tree.TreeCheckOwner(ctx, failOpen, owner, gen)
+ return checkOwner(ctx, firstElem.Forrest, lastElem.FromTree, failOpen,
+ owner, gen)
},
MinItem: containers.OptionalValue(lastElem.ToMinKey),
MaxItem: containers.OptionalValue(lastElem.ToMaxKey),
diff --git a/lib/btrfs/io3_btree.go b/lib/btrfs/io3_btree.go
index 50736cf..c9e1d79 100644
--- a/lib/btrfs/io3_btree.go
+++ b/lib/btrfs/io3_btree.go
@@ -44,7 +44,7 @@ func (fs *FS) AcquireNode(ctx context.Context, addr btrfsvol.LogicalAddr, exp bt
if nodeEntry.node != nil {
if err := exp.Check(nodeEntry.node); err != nil {
fs.cacheNodes.Release(addr)
- return nil, fmt.Errorf("btrfstree.ReadNode: node@%v: %w", addr, err) // fmt.Errorf("btrfs.FS.AcquireNode: node@%v: %w", addr, err)
+ return nil, fmt.Errorf("btrfs.FS.AcquireNode: node@%v: %w", addr, err)
}
}
diff --git a/lib/btrfsutil/old_rebuilt_forrest.go b/lib/btrfsutil/old_rebuilt_forrest.go
index 0a3106d..b03ddc2 100644
--- a/lib/btrfsutil/old_rebuilt_forrest.go
+++ b/lib/btrfsutil/old_rebuilt_forrest.go
@@ -367,7 +367,7 @@ func (tree oldRebuiltTree) TreeWalk(ctx context.Context, cbs btrfstree.TreeWalkH
if cbs.Node != nil && !visitedNodes.Has(indexItem.Value.Node.LAddr) {
nodePath := btrfstree.Path{
btrfstree.PathRoot{
- Tree: tree,
+ Forrest: tree.forrest,
TreeID: tree.ID,
ToAddr: indexItem.Value.Node.LAddr,
ToGeneration: indexItem.Value.Node.Generation,
@@ -386,7 +386,7 @@ func (tree oldRebuiltTree) TreeWalk(ctx context.Context, cbs btrfstree.TreeWalkH
item := node.BodyLeaf[indexItem.Value.Slot]
itemPath := btrfstree.Path{
btrfstree.PathRoot{
- Tree: tree,
+ Forrest: tree.forrest,
TreeID: tree.ID,
ToAddr: indexItem.Value.Node.LAddr,
ToGeneration: indexItem.Value.Node.Generation,
@@ -418,59 +418,28 @@ func (tree oldRebuiltTree) TreeWalk(ctx context.Context, cbs btrfstree.TreeWalkH
tree.forrest.ReleaseNode(node)
}
-// TreeCheckOwner implements btrfstree.Tree.
-func (tree oldRebuiltTree) TreeCheckOwner(ctx context.Context, failOpen bool, owner btrfsprim.ObjID, gen btrfsprim.Generation) error {
- var uuidTree oldRebuiltTree
- for {
- // Main.
- if owner == tree.ID {
- return nil
- }
- if tree.ParentUUID == (btrfsprim.UUID{}) {
- return fmt.Errorf("owner=%v is not acceptable in this tree",
- owner)
- }
- if gen > tree.ParentGen {
- return fmt.Errorf("claimed owner=%v might be acceptable in this tree (if generation<=%v) but not with claimed generation=%v",
- owner, tree.ParentGen, gen)
- }
-
- // Loop update.
- if uuidTree.forrest == nil {
- uuidTree = tree.forrest.RebuiltTree(ctx, btrfsprim.UUID_TREE_OBJECTID)
- if uuidTree.RootErr != nil {
- return nil //nolint:nilerr // fail open
- }
- }
- parentIDItem, err := uuidTree.TreeLookup(ctx, btrfsitem.UUIDToKey(tree.ParentUUID))
- if err != nil {
- if failOpen {
- return nil
- }
- return fmt.Errorf("unable to determine whether owner=%v generation=%v is acceptable: %w",
- owner, gen, err)
- }
- switch parentIDBody := parentIDItem.Body.(type) {
- case *btrfsitem.UUIDMap:
- tree = tree.forrest.RebuiltTree(ctx, parentIDBody.ObjID)
- if tree.RootErr != nil {
- if failOpen {
- return nil
- }
- return fmt.Errorf("unable to determine whether owner=%v generation=%v is acceptable: %w",
- owner, gen, tree.RootErr)
- }
- case *btrfsitem.Error:
- if failOpen {
- return nil
- }
- return fmt.Errorf("unable to determine whether owner=%v generation=%v is acceptable: %w",
- owner, gen, parentIDBody.Err)
- default:
- // This is a panic because the item decoder should not emit UUID_SUBVOL items as anything but
- // btrfsitem.UUIDMap or btrfsitem.Error without this code also being updated.
- panic(fmt.Errorf("should not happen: UUID_SUBVOL item has unexpected type: %T", parentIDBody))
- }
+// TreeParentID implements btrfstree.Tree.
+func (tree oldRebuiltTree) TreeParentID(ctx context.Context) (btrfsprim.ObjID, btrfsprim.Generation, error) {
+ if tree.ParentUUID == (btrfsprim.UUID{}) {
+ return 0, 0, nil
+ }
+ uuidTree := tree.forrest.RebuiltTree(ctx, btrfsprim.UUID_TREE_OBJECTID)
+ if uuidTree.RootErr != nil {
+ return 0, 0, uuidTree.RootErr
+ }
+ parentIDItem, err := uuidTree.TreeLookup(ctx, btrfsitem.UUIDToKey(tree.ParentUUID))
+ if err != nil {
+ return 0, 0, err
+ }
+ switch parentIDBody := parentIDItem.Body.(type) {
+ case *btrfsitem.UUIDMap:
+ return parentIDBody.ObjID, tree.ParentGen, nil
+ case *btrfsitem.Error:
+ return 0, 0, parentIDBody.Err
+ default:
+ // This is a panic because the item decoder should not emit UUID_SUBVOL items as anything but
+ // btrfsitem.UUIDMap or btrfsitem.Error without this code also being updated.
+ panic(fmt.Errorf("should not happen: UUID_SUBVOL item has unexpected type: %T", parentIDBody))
}
}
diff --git a/lib/btrfsutil/rebuilt_forrest.go b/lib/btrfsutil/rebuilt_forrest.go
index ba88bbc..6231563 100644
--- a/lib/btrfsutil/rebuilt_forrest.go
+++ b/lib/btrfsutil/rebuilt_forrest.go
@@ -278,7 +278,7 @@ func (ts *RebuiltForrest) RebuiltListRoots(ctx context.Context) map[btrfsprim.Ob
defer ts.treesMu.Unlock()
ret := make(map[btrfsprim.ObjID]containers.Set[btrfsvol.LogicalAddr])
for treeID, tree := range ts.trees {
- if tree != nil {
+ if tree != nil && len(tree.Roots) > 0 {
ret[treeID] = tree.Roots
}
}
diff --git a/lib/containers/arcache.go b/lib/containers/arcache.go
index 29ec030..deb80f0 100644
--- a/lib/containers/arcache.go
+++ b/lib/containers/arcache.go
@@ -504,9 +504,12 @@ func (c *arCache[K, V]) Acquire(ctx context.Context, k K) *V {
switch {
case c.liveByName[k] != nil: // cache-hit
entry = c.liveByName[k]
- if entry.List != &c.frequentPinned {
- // Move to frequentPinned (unless it's already
- // there; in which case, don't bother).
+ // Move to frequentPinned, unless:
+ //
+ // - it's already there; in which case, don't bother
+ // - it's in recentPinned; don't count "nested" uses
+ // as "frequent" uses.
+ if entry.List != &c.frequentPinned && entry.List != &c.recentPinned {
entry.List.Delete(entry)
c.frequentPinned.Store(entry)
}