diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/btrfs/btrfstree/btree.go | 14 | ||||
-rw-r--r-- | lib/btrfs/btrfstree/btree_tree.go | 82 | ||||
-rw-r--r-- | lib/btrfs/btrfstree/path.go | 47 | ||||
-rw-r--r-- | lib/btrfs/io3_btree.go | 2 | ||||
-rw-r--r-- | lib/btrfsutil/old_rebuilt_forrest.go | 79 | ||||
-rw-r--r-- | lib/btrfsutil/rebuilt_forrest.go | 2 | ||||
-rw-r--r-- | lib/containers/arcache.go | 9 |
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) } |