From d91f8ce17a6fc165fafd9dc921911233a69c34d2 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Mon, 9 Jan 2023 14:23:23 -0700 Subject: tree-wide: Migrate to the new ARCache --- lib/btrfsprogs/btrfsinspect/rebuildnodes/keyio/keyio.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'lib/btrfsprogs/btrfsinspect/rebuildnodes/keyio/keyio.go') diff --git a/lib/btrfsprogs/btrfsinspect/rebuildnodes/keyio/keyio.go b/lib/btrfsprogs/btrfsinspect/rebuildnodes/keyio/keyio.go index 64a9828..a85b78e 100644 --- a/lib/btrfsprogs/btrfsinspect/rebuildnodes/keyio/keyio.go +++ b/lib/btrfsprogs/btrfsinspect/rebuildnodes/keyio/keyio.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -48,7 +48,7 @@ type Handle struct { Names map[ItemPtr][]byte // DIR_INDEX Sizes map[ItemPtr]SizeAndErr // EXTENT_CSUM and EXTENT_DATA - cache *containers.LRUCache[btrfsvol.LogicalAddr, *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.Node]] + cache containers.ARCache[btrfsvol.LogicalAddr, *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.Node]] } func NewHandle(file diskio.File[btrfsvol.LogicalAddr], sb btrfstree.Superblock) *Handle { @@ -60,7 +60,9 @@ func NewHandle(file diskio.File[btrfsvol.LogicalAddr], sb btrfstree.Superblock) Names: make(map[ItemPtr][]byte), Sizes: make(map[ItemPtr]SizeAndErr), - cache: containers.NewLRUCache[btrfsvol.LogicalAddr, *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.Node]](textui.Tunable(8)), + cache: containers.ARCache[btrfsvol.LogicalAddr, *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.Node]]{ + MaxLen: textui.Tunable(8), + }, } } @@ -113,7 +115,7 @@ func (o *Handle) SetGraph(graph graph.Graph) { } func (o *Handle) readNode(ctx context.Context, laddr btrfsvol.LogicalAddr) *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.Node] { - if cached, ok := o.cache.Get(laddr); ok { + if cached, ok := o.cache.Load(laddr); ok { dlog.Tracef(ctx, "cache-hit node@%v", laddr) return cached } @@ -142,7 +144,7 @@ func (o *Handle) readNode(ctx context.Context, laddr btrfsvol.LogicalAddr) *disk panic(fmt.Errorf("should not happen: i/o error: %w", err)) } - o.cache.Add(laddr, ref) + o.cache.Store(laddr, ref) return ref } -- cgit v1.2.3-54-g00ecf From 677755c799c1b6b942349c7d9de836335c7bbf55 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Fri, 3 Feb 2023 11:32:52 -0700 Subject: btrfsitem: Have all Item implementations be pointers to structs --- lib/btrfs/Makefile | 2 +- lib/btrfs/btrfsitem/item_extent.go | 10 ++-- lib/btrfs/btrfsitem/item_freespacebitmap.go | 10 ++-- lib/btrfs/btrfsitem/item_inoderef.go | 12 +++-- lib/btrfs/btrfsitem/items.go | 18 ++++---- lib/btrfs/btrfsitem/items_gen.go | 48 +++++++++---------- lib/btrfs/btrfstree/ops.go | 2 +- lib/btrfs/btrfstree/root.go | 4 +- lib/btrfs/csums.go | 4 +- lib/btrfs/io2_lv.go | 4 +- lib/btrfs/io3_btree.go | 4 +- lib/btrfs/io4_fs.go | 52 +++++++++++---------- lib/btrfsprogs/btrfsinspect/print_tree.go | 52 ++++++++++----------- .../btrfsinspect/rebuildnodes/graph/graph.go | 6 +-- .../btrfsinspect/rebuildnodes/keyio/keyio.go | 10 ++-- .../btrfsinspect/rebuildnodes/rebuild.go | 10 ++-- .../btrfsinspect/rebuildnodes/rebuild_graph.go | 54 +++++++++++----------- lib/btrfsprogs/btrfsinspect/scandevices.go | 24 +++++----- 18 files changed, 166 insertions(+), 160 deletions(-) (limited to 'lib/btrfsprogs/btrfsinspect/rebuildnodes/keyio/keyio.go') diff --git a/lib/btrfs/Makefile b/lib/btrfs/Makefile index cbcaf9e..00c22e7 100644 --- a/lib/btrfs/Makefile +++ b/lib/btrfs/Makefile @@ -35,7 +35,7 @@ btrfsitem/items_gen.go: btrfsitem/items.txt $(MAKEFILE_LIST) echo 'var untypedObjID2gotype = map[btrfsprim.ObjID]reflect.Type{'; \ sed -En 's|UNTYPED=0:(.*) (.*)|btrfsprim.\1: reflect.TypeOf(\2{}),|p' $<; \ echo '}'; \ - sed -En 's,(.*)=(.*) (.+),\3,p' $< | LC_COLLATE=C sort -u | sed 's,.*,func (&) isItem() {},'; \ + sed -En 's,(.*)=(.*) (.+),\3,p' $< | LC_COLLATE=C sort -u | sed 's,.*,func (*&) isItem() {},'; \ } | gofmt >$@ files += btrfsitem/items_gen.go diff --git a/lib/btrfs/btrfsitem/item_extent.go b/lib/btrfs/btrfsitem/item_extent.go index 66aae1d..72371a9 100644 --- a/lib/btrfs/btrfsitem/item_extent.go +++ b/lib/btrfs/btrfsitem/item_extent.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -114,8 +114,8 @@ func (o *ExtentInlineRef) UnmarshalBinary(dat []byte) (int, error) { return n, err } case EXTENT_DATA_REF_KEY: - var dref ExtentDataRef - _n, err := binstruct.Unmarshal(dat[n:], &dref) + dref := new(ExtentDataRef) + _n, err := binstruct.Unmarshal(dat[n:], dref) n += _n o.Body = dref if err != nil { @@ -127,8 +127,8 @@ func (o *ExtentInlineRef) UnmarshalBinary(dat []byte) (int, error) { if err != nil { return n, err } - var sref SharedDataRef - _n, err = binstruct.Unmarshal(dat[n:], &sref) + sref := new(SharedDataRef) + _n, err = binstruct.Unmarshal(dat[n:], sref) n += _n o.Body = sref if err != nil { diff --git a/lib/btrfs/btrfsitem/item_freespacebitmap.go b/lib/btrfs/btrfsitem/item_freespacebitmap.go index ad46204..742d126 100644 --- a/lib/btrfs/btrfsitem/item_freespacebitmap.go +++ b/lib/btrfs/btrfsitem/item_freespacebitmap.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -6,13 +6,15 @@ package btrfsitem // key.objectid = object ID of the FreeSpaceInfo (logical_addr) // key.offset = offset of the FreeSpaceInfo (size) -type FreeSpaceBitmap []byte // FREE_SPACE_BITMAP=200 +type FreeSpaceBitmap struct { // FREE_SPACE_BITMAP=200 + Bitmap []byte +} func (o *FreeSpaceBitmap) UnmarshalBinary(dat []byte) (int, error) { - *o = dat + o.Bitmap = dat return len(dat), nil } func (o FreeSpaceBitmap) MarshalBinary() ([]byte, error) { - return []byte(o), nil + return o.Bitmap, nil } diff --git a/lib/btrfs/btrfsitem/item_inoderef.go b/lib/btrfs/btrfsitem/item_inoderef.go index 083f19e..c90fe44 100644 --- a/lib/btrfs/btrfsitem/item_inoderef.go +++ b/lib/btrfs/btrfsitem/item_inoderef.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -16,10 +16,12 @@ import ( // // Might have multiple entries if the same file has multiple hardlinks // in the same directory. -type InodeRefs []InodeRef // INODE_REF=12 +type InodeRefs struct { // INODE_REF=12 + Refs []InodeRef +} func (o *InodeRefs) UnmarshalBinary(dat []byte) (int, error) { - *o = nil + o.Refs = nil n := 0 for n < len(dat) { var ref InodeRef @@ -28,14 +30,14 @@ func (o *InodeRefs) UnmarshalBinary(dat []byte) (int, error) { if err != nil { return n, err } - *o = append(*o, ref) + o.Refs = append(o.Refs, ref) } return n, nil } func (o InodeRefs) MarshalBinary() ([]byte, error) { var dat []byte - for _, ref := range o { + for _, ref := range o.Refs { _dat, err := binstruct.Marshal(ref) dat = append(dat, _dat...) if err != nil { diff --git a/lib/btrfs/btrfsitem/items.go b/lib/btrfs/btrfsitem/items.go index 67f96fa..9964e2d 100644 --- a/lib/btrfs/btrfsitem/items.go +++ b/lib/btrfs/btrfsitem/items.go @@ -25,7 +25,7 @@ type Error struct { Err error } -func (Error) isItem() {} +func (*Error) isItem() {} func (o Error) MarshalBinary() ([]byte, error) { return o.Dat, nil @@ -43,7 +43,7 @@ func UnmarshalItem(key btrfsprim.Key, csumType btrfssum.CSumType, dat []byte) It var ok bool gotyp, ok = untypedObjID2gotype[key.ObjectID] if !ok { - return Error{ + return &Error{ Dat: dat, Err: fmt.Errorf("btrfsitem.UnmarshalItem({ItemType:%v, ObjectID:%v}, dat): unknown object ID for untyped item", key.ItemType, key.ObjectID), @@ -53,31 +53,31 @@ func UnmarshalItem(key btrfsprim.Key, csumType btrfssum.CSumType, dat []byte) It var ok bool gotyp, ok = keytype2gotype[key.ItemType] if !ok { - return Error{ + return &Error{ Dat: dat, Err: fmt.Errorf("btrfsitem.UnmarshalItem({ItemType:%v}, dat): unknown item type", key.ItemType), } } } - retPtr := reflect.New(gotyp) - if csums, ok := retPtr.Interface().(*ExtentCSum); ok { + ptr := reflect.New(gotyp) + if csums, ok := ptr.Interface().(*ExtentCSum); ok { csums.ChecksumSize = csumType.Size() csums.Addr = btrfsvol.LogicalAddr(key.Offset) } - n, err := binstruct.Unmarshal(dat, retPtr.Interface()) + n, err := binstruct.Unmarshal(dat, ptr.Interface()) if err != nil { - return Error{ + return &Error{ Dat: dat, Err: fmt.Errorf("btrfsitem.UnmarshalItem({ItemType:%v}, dat): %w", key.ItemType, err), } } if n < len(dat) { - return Error{ + return &Error{ Dat: dat, Err: fmt.Errorf("btrfsitem.UnmarshalItem({ItemType:%v}, dat): left over data: got %v bytes but only consumed %v", key.ItemType, len(dat), n), } } //nolint:forcetypeassert // items_gen.go has all types in keytype2gotype implement the Item interface. - return retPtr.Elem().Interface().(Item) + return ptr.Interface().(Item) } diff --git a/lib/btrfs/btrfsitem/items_gen.go b/lib/btrfs/btrfsitem/items_gen.go index 9daef81..21c6795 100644 --- a/lib/btrfs/btrfsitem/items_gen.go +++ b/lib/btrfs/btrfsitem/items_gen.go @@ -80,27 +80,27 @@ var untypedObjID2gotype = map[btrfsprim.ObjID]reflect.Type{ btrfsprim.FREE_SPACE_OBJECTID: reflect.TypeOf(FreeSpaceHeader{}), } -func (BlockGroup) isItem() {} -func (Chunk) isItem() {} -func (Dev) isItem() {} -func (DevExtent) isItem() {} -func (DevStats) isItem() {} -func (DirEntry) isItem() {} -func (Empty) isItem() {} -func (Extent) isItem() {} -func (ExtentCSum) isItem() {} -func (ExtentDataRef) isItem() {} -func (FileExtent) isItem() {} -func (FreeSpaceBitmap) isItem() {} -func (FreeSpaceHeader) isItem() {} -func (FreeSpaceInfo) isItem() {} -func (Inode) isItem() {} -func (InodeRefs) isItem() {} -func (Metadata) isItem() {} -func (QGroupInfo) isItem() {} -func (QGroupLimit) isItem() {} -func (QGroupStatus) isItem() {} -func (Root) isItem() {} -func (RootRef) isItem() {} -func (SharedDataRef) isItem() {} -func (UUIDMap) isItem() {} +func (*BlockGroup) isItem() {} +func (*Chunk) isItem() {} +func (*Dev) isItem() {} +func (*DevExtent) isItem() {} +func (*DevStats) isItem() {} +func (*DirEntry) isItem() {} +func (*Empty) isItem() {} +func (*Extent) isItem() {} +func (*ExtentCSum) isItem() {} +func (*ExtentDataRef) isItem() {} +func (*FileExtent) isItem() {} +func (*FreeSpaceBitmap) isItem() {} +func (*FreeSpaceHeader) isItem() {} +func (*FreeSpaceInfo) isItem() {} +func (*Inode) isItem() {} +func (*InodeRefs) isItem() {} +func (*Metadata) isItem() {} +func (*QGroupInfo) isItem() {} +func (*QGroupLimit) isItem() {} +func (*QGroupStatus) isItem() {} +func (*Root) isItem() {} +func (*RootRef) isItem() {} +func (*SharedDataRef) isItem() {} +func (*UUIDMap) isItem() {} diff --git a/lib/btrfs/btrfstree/ops.go b/lib/btrfs/btrfstree/ops.go index cdacef9..bda4ac8 100644 --- a/lib/btrfs/btrfstree/ops.go +++ b/lib/btrfs/btrfstree/ops.go @@ -207,7 +207,7 @@ func (fs TreeOperatorImpl) treeWalk(ctx context.Context, path TreePath, errHandl ToKey: item.Key, ToMaxKey: item.Key, }) - if errBody, isErr := item.Body.(btrfsitem.Error); isErr { + if errBody, isErr := item.Body.(*btrfsitem.Error); isErr { if cbs.BadItem == nil { errHandle(&TreeError{Path: itemPath, Err: errBody.Err}) } else { diff --git a/lib/btrfs/btrfstree/root.go b/lib/btrfs/btrfstree/root.go index 319904b..ace2b49 100644 --- a/lib/btrfs/btrfstree/root.go +++ b/lib/btrfs/btrfstree/root.go @@ -72,14 +72,14 @@ func LookupTreeRoot(fs TreeOperator, sb Superblock, treeID btrfsprim.ObjID) (*Tr return nil, err } switch rootItemBody := rootItem.Body.(type) { - case btrfsitem.Root: + case *btrfsitem.Root: return &TreeRoot{ TreeID: treeID, RootNode: rootItemBody.ByteNr, Level: rootItemBody.Level, Generation: rootItemBody.Generation, }, nil - case btrfsitem.Error: + case *btrfsitem.Error: return nil, fmt.Errorf("malformed ROOT_ITEM for tree %v: %w", treeID, rootItemBody.Err) default: panic(fmt.Errorf("should not happen: ROOT_ITEM has unexpected item type: %T", rootItemBody)) diff --git a/lib/btrfs/csums.go b/lib/btrfs/csums.go index a32f090..2bfa588 100644 --- a/lib/btrfs/csums.go +++ b/lib/btrfs/csums.go @@ -60,9 +60,9 @@ func LookupCSum(fs btrfstree.TreeOperator, alg btrfssum.CSumType, laddr btrfsvol return btrfssum.SumRun[btrfsvol.LogicalAddr]{}, fmt.Errorf("item type is %v, not EXTENT_CSUM", item.Key.ItemType) } switch body := item.Body.(type) { - case btrfsitem.ExtentCSum: + case *btrfsitem.ExtentCSum: return body.SumRun, nil - case btrfsitem.Error: + case *btrfsitem.Error: return btrfssum.SumRun[btrfsvol.LogicalAddr]{}, body.Err default: panic(fmt.Errorf("should not happen: EXTENT_CSUM has unexpected item type: %T", body)) diff --git a/lib/btrfs/io2_lv.go b/lib/btrfs/io2_lv.go index ac7ea70..856ac20 100644 --- a/lib/btrfs/io2_lv.go +++ b/lib/btrfs/io2_lv.go @@ -173,13 +173,13 @@ func (fs *FS) initDev(ctx context.Context, sb btrfstree.Superblock) error { return nil } switch itemBody := item.Body.(type) { - case btrfsitem.Chunk: + case *btrfsitem.Chunk: for _, mapping := range itemBody.Mappings(item.Key) { if err := fs.LV.AddMapping(mapping); err != nil { return err } } - case btrfsitem.Error: + case *btrfsitem.Error: // do nothing default: // This is a panic because the item decoder should not emit CHUNK_ITEM items as diff --git a/lib/btrfs/io3_btree.go b/lib/btrfs/io3_btree.go index 8ec4b41..18df98e 100644 --- a/lib/btrfs/io3_btree.go +++ b/lib/btrfs/io3_btree.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -43,7 +43,7 @@ func (fs *FS) populateTreeUUIDs(ctx context.Context) { }, btrfstree.TreeWalkHandler{ Item: func(_ btrfstree.TreePath, item btrfstree.Item) error { - itemBody, ok := item.Body.(btrfsitem.Root) + itemBody, ok := item.Body.(*btrfsitem.Root) if !ok { return nil } diff --git a/lib/btrfs/io4_fs.go b/lib/btrfs/io4_fs.go index adc0928..c21cafc 100644 --- a/lib/btrfs/io4_fs.go +++ b/lib/btrfs/io4_fs.go @@ -88,9 +88,9 @@ func (sv *Subvolume) init() { sv.rootErr = err } else { switch rootBody := root.Body.(type) { - case btrfsitem.Root: - sv.rootVal = rootBody - case btrfsitem.Error: + case *btrfsitem.Root: + sv.rootVal = *rootBody + case *btrfsitem.Error: sv.rootErr = fmt.Errorf("FS_TREE ROOT_ITEM has malformed body: %w", rootBody.Err) default: panic(fmt.Errorf("should not happen: ROOT_ITEM has unexpected item type: %T", rootBody)) @@ -126,9 +126,10 @@ func (sv *Subvolume) LoadBareInode(inode btrfsprim.ObjID) (*BareInode, error) { } switch itemBody := item.Body.(type) { - case btrfsitem.Inode: - val.InodeItem = &itemBody - case btrfsitem.Error: + case *btrfsitem.Inode: + bodyCopy := *itemBody + val.InodeItem = &bodyCopy + case *btrfsitem.Error: val.Errs = append(val.Errs, fmt.Errorf("malformed inode: %w", itemBody.Err)) default: panic(fmt.Errorf("should not happen: INODE_ITEM has unexpected item type: %T", itemBody)) @@ -164,24 +165,25 @@ func (sv *Subvolume) LoadFullInode(inode btrfsprim.ObjID) (*FullInode, error) { switch item.Key.ItemType { case btrfsitem.INODE_ITEM_KEY: switch itemBody := item.Body.(type) { - case btrfsitem.Inode: + case *btrfsitem.Inode: if val.InodeItem != nil { if !reflect.DeepEqual(itemBody, *val.InodeItem) { val.Errs = append(val.Errs, fmt.Errorf("multiple inodes")) } continue } - val.InodeItem = &itemBody - case btrfsitem.Error: + bodyCopy := *itemBody + val.InodeItem = &bodyCopy + case *btrfsitem.Error: val.Errs = append(val.Errs, fmt.Errorf("malformed INODE_ITEM: %w", itemBody.Err)) default: panic(fmt.Errorf("should not happen: INODE_ITEM has unexpected item type: %T", itemBody)) } case btrfsitem.XATTR_ITEM_KEY: switch itemBody := item.Body.(type) { - case btrfsitem.DirEntry: + case *btrfsitem.DirEntry: val.XAttrs[string(itemBody.Name)] = string(itemBody.Data) - case btrfsitem.Error: + case *btrfsitem.Error: val.Errs = append(val.Errs, fmt.Errorf("malformed XATTR_ITEM: %w", itemBody.Err)) default: panic(fmt.Errorf("should not happen: XATTR_ITEM has unexpected item type: %T", itemBody)) @@ -225,15 +227,15 @@ func (dir *Dir) populate() { switch item.Key.ItemType { case btrfsitem.INODE_REF_KEY: switch body := item.Body.(type) { - case btrfsitem.InodeRefs: - if len(body) != 1 { + case *btrfsitem.InodeRefs: + if len(body.Refs) != 1 { dir.Errs = append(dir.Errs, fmt.Errorf("INODE_REF item with %d entries on a directory", - len(body))) + len(body.Refs))) continue } ref := InodeRef{ Inode: btrfsprim.ObjID(item.Key.Offset), - InodeRef: body[0], + InodeRef: body.Refs[0], } if dir.DotDot != nil { if !reflect.DeepEqual(ref, *dir.DotDot) { @@ -242,14 +244,14 @@ func (dir *Dir) populate() { continue } dir.DotDot = &ref - case btrfsitem.Error: + case *btrfsitem.Error: dir.Errs = append(dir.Errs, fmt.Errorf("malformed INODE_REF: %w", body.Err)) default: panic(fmt.Errorf("should not happen: INODE_REF has unexpected item type: %T", body)) } case btrfsitem.DIR_ITEM_KEY: switch entry := item.Body.(type) { - case btrfsitem.DirEntry: + case *btrfsitem.DirEntry: namehash := btrfsitem.NameHash(entry.Name) if namehash != item.Key.Offset { dir.Errs = append(dir.Errs, fmt.Errorf("direntry crc32c mismatch: key=%#x crc32c(%q)=%#x", @@ -262,8 +264,8 @@ func (dir *Dir) populate() { } continue } - dir.ChildrenByName[string(entry.Name)] = entry - case btrfsitem.Error: + dir.ChildrenByName[string(entry.Name)] = *entry + case *btrfsitem.Error: dir.Errs = append(dir.Errs, fmt.Errorf("malformed DIR_ITEM: %w", entry.Err)) default: panic(fmt.Errorf("should not happen: DIR_ITEM has unexpected item type: %T", entry)) @@ -271,15 +273,15 @@ func (dir *Dir) populate() { case btrfsitem.DIR_INDEX_KEY: index := item.Key.Offset switch entry := item.Body.(type) { - case btrfsitem.DirEntry: + case *btrfsitem.DirEntry: if other, exists := dir.ChildrenByIndex[index]; exists { if !reflect.DeepEqual(entry, other) { dir.Errs = append(dir.Errs, fmt.Errorf("multiple instances of direntry index %v", index)) } continue } - dir.ChildrenByIndex[index] = entry - case btrfsitem.Error: + dir.ChildrenByIndex[index] = *entry + case *btrfsitem.Error: dir.Errs = append(dir.Errs, fmt.Errorf("malformed DIR_INDEX: %w", entry.Err)) default: panic(fmt.Errorf("should not happen: DIR_INDEX has unexpected item type: %T", entry)) @@ -361,12 +363,12 @@ func (file *File) populate() { // TODO case btrfsitem.EXTENT_DATA_KEY: switch itemBody := item.Body.(type) { - case btrfsitem.FileExtent: + case *btrfsitem.FileExtent: file.Extents = append(file.Extents, FileExtent{ OffsetWithinFile: int64(item.Key.Offset), - FileExtent: itemBody, + FileExtent: *itemBody, }) - case btrfsitem.Error: + case *btrfsitem.Error: file.Errs = append(file.Errs, fmt.Errorf("malformed EXTENT_DATA: %w", itemBody.Err)) default: panic(fmt.Errorf("should not happen: EXTENT_DATA has unexpected item type: %T", itemBody)) diff --git a/lib/btrfsprogs/btrfsinspect/print_tree.go b/lib/btrfsprogs/btrfsinspect/print_tree.go index 3807df5..409ce0c 100644 --- a/lib/btrfsprogs/btrfsinspect/print_tree.go +++ b/lib/btrfsprogs/btrfsinspect/print_tree.go @@ -121,11 +121,11 @@ func printTree(ctx context.Context, out io.Writer, fs *btrfs.FS, treeID btrfspri itemOffset, itemSize) switch body := item.Body.(type) { - case btrfsitem.FreeSpaceHeader: + case *btrfsitem.FreeSpaceHeader: textui.Fprintf(out, "\t\tlocation %v\n", fmtKey(body.Location)) textui.Fprintf(out, "\t\tcache generation %v entries %v bitmaps %v\n", body.Generation, body.NumEntries, body.NumBitmaps) - case btrfsitem.Inode: + case *btrfsitem.Inode: textui.Fprintf(out, ""+ "\t\tgeneration %v transid %v size %v nbytes %v\n"+ "\t\tblock group %v mode %o links %v uid %v gid %v rdev %v\n"+ @@ -137,14 +137,14 @@ func printTree(ctx context.Context, out io.Writer, fs *btrfs.FS, treeID btrfspri textui.Fprintf(out, "\t\tctime %v\n", fmtTime(body.CTime)) textui.Fprintf(out, "\t\tmtime %v\n", fmtTime(body.MTime)) textui.Fprintf(out, "\t\totime %v\n", fmtTime(body.OTime)) - case btrfsitem.InodeRefs: - for _, ref := range body { + case *btrfsitem.InodeRefs: + for _, ref := range body.Refs { textui.Fprintf(out, "\t\tindex %v namelen %v name: %s\n", ref.Index, ref.NameLen, ref.Name) } // case btrfsitem.INODE_EXTREF_KEY: // // TODO - case btrfsitem.DirEntry: + case *btrfsitem.DirEntry: textui.Fprintf(out, "\t\tlocation %v type %v\n", fmtKey(body.Location), body.Type) textui.Fprintf(out, "\t\ttransid %v data_len %v name_len %v\n", @@ -155,7 +155,7 @@ func printTree(ctx context.Context, out io.Writer, fs *btrfs.FS, treeID btrfspri } // case btrfsitem.DIR_LOG_INDEX_KEY, btrfsitem.DIR_LOG_ITEM_KEY: // // TODO - case btrfsitem.Root: + case *btrfsitem.Root: textui.Fprintf(out, "\t\tgeneration %v root_dirid %v bytenr %d byte_limit %v bytes_used %v\n", body.Generation, body.RootDirID, body.ByteNr, body.ByteLimit, body.BytesUsed) textui.Fprintf(out, "\t\tlast_snapshot %v flags %v refs %v\n", @@ -175,7 +175,7 @@ func printTree(ctx context.Context, out io.Writer, fs *btrfs.FS, treeID btrfspri textui.Fprintf(out, "\t\tstime %v\n", fmtTime(body.STime)) textui.Fprintf(out, "\t\trtime %v\n", fmtTime(body.RTime)) } - case btrfsitem.RootRef: + case *btrfsitem.RootRef: var tag string switch item.Key.ItemType { case btrfsitem.ROOT_REF_KEY: @@ -187,7 +187,7 @@ func printTree(ctx context.Context, out io.Writer, fs *btrfs.FS, treeID btrfspri } textui.Fprintf(out, "\t\troot %v key dirid %v sequence %v name %s\n", tag, body.DirID, body.Sequence, body.Name) - case btrfsitem.Extent: + case *btrfsitem.Extent: textui.Fprintf(out, "\t\trefs %v gen %v flags %v\n", body.Head.Refs, body.Head.Generation, body.Head.Flags) if body.Head.Flags.Has(btrfsitem.EXTENT_FLAG_TREE_BLOCK) { @@ -195,7 +195,7 @@ func printTree(ctx context.Context, out io.Writer, fs *btrfs.FS, treeID btrfspri fmtKey(body.Info.Key), body.Info.Level) } printExtentInlineRefs(out, body.Refs) - case btrfsitem.Metadata: + case *btrfsitem.Metadata: textui.Fprintf(out, "\t\trefs %v gen %v flags %v\n", body.Head.Refs, body.Head.Generation, body.Head.Flags) textui.Fprintf(out, "\t\ttree block skinny level %v\n", item.Key.Offset) @@ -204,7 +204,7 @@ func printTree(ctx context.Context, out io.Writer, fs *btrfs.FS, treeID btrfspri // // TODO // case btrfsitem.SHARED_DATA_REF_KEY: // // TODO - case btrfsitem.ExtentCSum: + case *btrfsitem.ExtentCSum: start := btrfsvol.LogicalAddr(item.Key.Offset) textui.Fprintf(out, "\t\trange start %d end %d length %d", start, start.Add(body.Size()), body.Size()) @@ -222,7 +222,7 @@ func printTree(ctx context.Context, out io.Writer, fs *btrfs.FS, treeID btrfspri return nil }) textui.Fprintf(out, "\n") - case btrfsitem.FileExtent: + case *btrfsitem.FileExtent: textui.Fprintf(out, "\t\tgeneration %v type %v\n", body.Generation, body.Type) switch body.Type { @@ -249,15 +249,15 @@ func printTree(ctx context.Context, out io.Writer, fs *btrfs.FS, treeID btrfspri default: textui.Fprintf(out, "\t\t(error) unknown file extent type %v", body.Type) } - case btrfsitem.BlockGroup: + case *btrfsitem.BlockGroup: textui.Fprintf(out, "\t\tblock group used %v chunk_objectid %v flags %v\n", body.Used, body.ChunkObjectID, body.Flags) - case btrfsitem.FreeSpaceInfo: + case *btrfsitem.FreeSpaceInfo: textui.Fprintf(out, "\t\tfree space info extent count %v flags %d\n", body.ExtentCount, body.Flags) - case btrfsitem.FreeSpaceBitmap: + case *btrfsitem.FreeSpaceBitmap: textui.Fprintf(out, "\t\tfree space bitmap\n") - case btrfsitem.Chunk: + case *btrfsitem.Chunk: textui.Fprintf(out, "\t\tlength %d owner %d stripe_len %v type %v\n", body.Head.Size, body.Head.Owner, body.Head.StripeLen, body.Head.Type) textui.Fprintf(out, "\t\tio_align %v io_width %v sector_size %v\n", @@ -270,7 +270,7 @@ func printTree(ctx context.Context, out io.Writer, fs *btrfs.FS, treeID btrfspri textui.Fprintf(out, "\t\t\tdev_uuid %v\n", stripe.DeviceUUID) } - case btrfsitem.Dev: + case *btrfsitem.Dev: textui.Fprintf(out, ""+ "\t\tdevid %d total_bytes %v bytes_used %v\n"+ "\t\tio_align %v io_width %v sector_size %v type %v\n"+ @@ -284,18 +284,18 @@ func printTree(ctx context.Context, out io.Writer, fs *btrfs.FS, treeID btrfspri body.SeekSpeed, body.Bandwidth, body.DevUUID, body.FSUUID) - case btrfsitem.DevExtent: + case *btrfsitem.DevExtent: textui.Fprintf(out, ""+ "\t\tdev extent chunk_tree %d\n"+ "\t\tchunk_objectid %v chunk_offset %d length %d\n"+ "\t\tchunk_tree_uuid %v\n", body.ChunkTree, body.ChunkObjectID, body.ChunkOffset, body.Length, body.ChunkTreeUUID) - case btrfsitem.QGroupStatus: + case *btrfsitem.QGroupStatus: textui.Fprintf(out, ""+ "\t\tversion %v generation %v flags %v scan %d\n", body.Version, body.Generation, body.Flags, body.RescanProgress) - case btrfsitem.QGroupInfo: + case *btrfsitem.QGroupInfo: textui.Fprintf(out, ""+ "\t\tgeneration %v\n"+ "\t\treferenced %d referenced_compressed %d\n"+ @@ -303,7 +303,7 @@ func printTree(ctx context.Context, out io.Writer, fs *btrfs.FS, treeID btrfspri body.Generation, body.ReferencedBytes, body.ReferencedBytesCompressed, body.ExclusiveBytes, body.ExclusiveBytesCompressed) - case btrfsitem.QGroupLimit: + case *btrfsitem.QGroupLimit: textui.Fprintf(out, ""+ "\t\tflags %x\n"+ "\t\tmax_referenced %d max_exclusive %d\n"+ @@ -311,11 +311,11 @@ func printTree(ctx context.Context, out io.Writer, fs *btrfs.FS, treeID btrfspri uint64(body.Flags), body.MaxReferenced, body.MaxExclusive, body.RsvReferenced, body.RsvExclusive) - case btrfsitem.UUIDMap: + case *btrfsitem.UUIDMap: textui.Fprintf(out, "\t\tsubvol_id %d\n", body.ObjID) // case btrfsitem.STRING_ITEM_KEY: // // TODO - case btrfsitem.DevStats: + case *btrfsitem.DevStats: textui.Fprintf(out, "\t\tpersistent item objectid %v offset %v\n", item.Key.ObjectID.Format(item.Key.ItemType), item.Key.Offset) switch item.Key.ObjectID { @@ -332,7 +332,7 @@ func printTree(ctx context.Context, out io.Writer, fs *btrfs.FS, treeID btrfspri } // case btrfsitem.TEMPORARY_ITEM_KEY: // // TODO - case btrfsitem.Empty: + case *btrfsitem.Empty: switch item.Key.ItemType { case btrfsitem.ORPHAN_ITEM_KEY: // 48 textui.Fprintf(out, "\t\torphan item\n") @@ -351,7 +351,7 @@ func printTree(ctx context.Context, out io.Writer, fs *btrfs.FS, treeID btrfspri default: textui.Fprintf(out, "\t\t(error) unhandled empty item type: %v\n", item.Key.ItemType) } - case btrfsitem.Error: + case *btrfsitem.Error: textui.Fprintf(out, "\t\t(error) error item: %v\n", body.Err) default: textui.Fprintf(out, "\t\t(error) unhandled item type: %T\n", body) @@ -423,10 +423,10 @@ func printExtentInlineRefs(out io.Writer, refs []btrfsitem.ExtentInlineRef) { default: textui.Fprintf(out, "\t\t(error) unexpected empty sub-item type: %v\n", ref.Type) } - case btrfsitem.ExtentDataRef: + case *btrfsitem.ExtentDataRef: textui.Fprintf(out, "\t\textent data backref root %v objectid %v offset %v count %v\n", subitem.Root, subitem.ObjectID, subitem.Offset, subitem.Count) - case btrfsitem.SharedDataRef: + case *btrfsitem.SharedDataRef: textui.Fprintf(out, "\t\tshared data backref parent %v count %v\n", ref.Offset, subitem.Count) default: diff --git a/lib/btrfsprogs/btrfsinspect/rebuildnodes/graph/graph.go b/lib/btrfsprogs/btrfsinspect/rebuildnodes/graph/graph.go index cf86d74..c04fec0 100644 --- a/lib/btrfsprogs/btrfsinspect/rebuildnodes/graph/graph.go +++ b/lib/btrfsprogs/btrfsinspect/rebuildnodes/graph/graph.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -151,7 +151,7 @@ func (g Graph) InsertNode(nodeRef *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.No if nodeRef.Data.Head.Level == 0 { cnt := 0 for _, item := range nodeRef.Data.BodyLeaf { - if _, ok := item.Body.(btrfsitem.Root); ok { + if _, ok := item.Body.(*btrfsitem.Root); ok { cnt++ } } @@ -161,7 +161,7 @@ func (g Graph) InsertNode(nodeRef *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.No g.Nodes[nodeRef.Addr] = nodeData for i, item := range nodeRef.Data.BodyLeaf { keys[i] = item.Key - if itemBody, ok := item.Body.(btrfsitem.Root); ok { + if itemBody, ok := item.Body.(*btrfsitem.Root); ok { kps = append(kps, Edge{ FromRoot: nodeRef.Addr, FromItem: i, diff --git a/lib/btrfsprogs/btrfsinspect/rebuildnodes/keyio/keyio.go b/lib/btrfsprogs/btrfsinspect/rebuildnodes/keyio/keyio.go index a85b78e..149706d 100644 --- a/lib/btrfsprogs/btrfsinspect/rebuildnodes/keyio/keyio.go +++ b/lib/btrfsprogs/btrfsinspect/rebuildnodes/keyio/keyio.go @@ -73,27 +73,27 @@ func (o *Handle) InsertNode(nodeRef *diskio.Ref[btrfsvol.LogicalAddr, btrfstree. Idx: i, } switch itemBody := item.Body.(type) { - case btrfsitem.Inode: + case *btrfsitem.Inode: o.Flags[ptr] = FlagsAndErr{ NoDataSum: itemBody.Flags.Has(btrfsitem.INODE_NODATASUM), Err: nil, } - case btrfsitem.DirEntry: + case *btrfsitem.DirEntry: if item.Key.ItemType == btrfsprim.DIR_INDEX_KEY { o.Names[ptr] = append([]byte(nil), itemBody.Name...) } - case btrfsitem.ExtentCSum: + case *btrfsitem.ExtentCSum: o.Sizes[ptr] = SizeAndErr{ Size: uint64(itemBody.Size()), Err: nil, } - case btrfsitem.FileExtent: + case *btrfsitem.FileExtent: size, err := itemBody.Size() o.Sizes[ptr] = SizeAndErr{ Size: uint64(size), Err: err, } - case btrfsitem.Error: + case *btrfsitem.Error: switch item.Key.ItemType { case btrfsprim.INODE_ITEM_KEY: o.Flags[ptr] = FlagsAndErr{ diff --git a/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuild.go b/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuild.go index bd29278..624441f 100644 --- a/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuild.go +++ b/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuild.go @@ -290,9 +290,9 @@ func (o *rebuilder) cbLookupRoot(ctx context.Context, tree btrfsprim.ObjID) (off o.ioErr(ctx, fmt.Errorf("could not read previously read item: %v", key)) } switch itemBody := itemBody.(type) { - case btrfsitem.Root: - return btrfsprim.Generation(key.Offset), itemBody, true - case btrfsitem.Error: + case *btrfsitem.Root: + return btrfsprim.Generation(key.Offset), *itemBody, true + case *btrfsitem.Error: o.fsErr(ctx, fmt.Errorf("error decoding item: %v: %w", key, itemBody.Err)) return 0, btrfsitem.Root{}, false default: @@ -315,9 +315,9 @@ func (o *rebuilder) cbLookupUUID(ctx context.Context, uuid btrfsprim.UUID) (id b o.ioErr(ctx, fmt.Errorf("could not read previously read item: %v", key)) } switch itemBody := itemBody.(type) { - case btrfsitem.UUIDMap: + case *btrfsitem.UUIDMap: return itemBody.ObjID, true - case btrfsitem.Error: + case *btrfsitem.Error: o.fsErr(ctx, fmt.Errorf("error decoding item: %v: %w", key, itemBody.Err)) return 0, false default: diff --git a/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuild_graph.go b/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuild_graph.go index 9e40465..710030c 100644 --- a/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuild_graph.go +++ b/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuild_graph.go @@ -50,7 +50,7 @@ func handleItem(o rebuildCallbacks, ctx context.Context, treeID btrfsprim.ObjID, // https://btrfs.wiki.kernel.org/index.php/File:References.png (from the page // https://btrfs.wiki.kernel.org/index.php/Data_Structures ) switch body := item.Body.(type) { - case btrfsitem.BlockGroup: + case *btrfsitem.BlockGroup: o.want(ctx, "Chunk", btrfsprim.CHUNK_TREE_OBJECTID, body.ChunkObjectID, @@ -60,22 +60,22 @@ func handleItem(o rebuildCallbacks, ctx context.Context, treeID btrfsprim.ObjID, item.Key.ObjectID, btrfsitem.FREE_SPACE_INFO_KEY, item.Key.Offset) - case btrfsitem.Chunk: + case *btrfsitem.Chunk: o.want(ctx, "owning Root", btrfsprim.ROOT_TREE_OBJECTID, body.Head.Owner, btrfsitem.ROOT_ITEM_KEY) - case btrfsitem.Dev: + case *btrfsitem.Dev: // nothing - case btrfsitem.DevExtent: + case *btrfsitem.DevExtent: o.wantOff(ctx, "Chunk", body.ChunkTree, body.ChunkObjectID, btrfsitem.CHUNK_ITEM_KEY, uint64(body.ChunkOffset)) - case btrfsitem.DevStats: + case *btrfsitem.DevStats: // nothing - case btrfsitem.DirEntry: + case *btrfsitem.DirEntry: // containing-directory o.wantOff(ctx, "containing dir inode", treeID, @@ -126,9 +126,9 @@ func handleItem(o rebuildCallbacks, ctx context.Context, treeID btrfsprim.ObjID, o.fsErr(ctx, fmt.Errorf("DirEntry: unexpected .Location.ItemType=%v", body.Location.ItemType)) } } - case btrfsitem.Empty: + case *btrfsitem.Empty: // nothing - case btrfsitem.Extent: + case *btrfsitem.Extent: // if body.Head.Flags.Has(btrfsitem.EXTENT_FLAG_TREE_BLOCK) { // // Supposedly this flag indicates that // // body.Info.Key identifies a node by the @@ -140,7 +140,7 @@ func handleItem(o rebuildCallbacks, ctx context.Context, treeID btrfsprim.ObjID, switch refBody := ref.Body.(type) { case nil: // nothing - case btrfsitem.ExtentDataRef: + case *btrfsitem.ExtentDataRef: o.wantOff(ctx, "referencing Inode", refBody.Root, refBody.ObjectID, @@ -151,7 +151,7 @@ func handleItem(o rebuildCallbacks, ctx context.Context, treeID btrfsprim.ObjID, refBody.ObjectID, btrfsitem.EXTENT_DATA_KEY, uint64(refBody.Offset)) - case btrfsitem.SharedDataRef: + case *btrfsitem.SharedDataRef: // nothing default: // This is a panic because the item decoder should not emit a new @@ -159,9 +159,9 @@ func handleItem(o rebuildCallbacks, ctx context.Context, treeID btrfsprim.ObjID, panic(fmt.Errorf("should not happen: Extent: unexpected .Refs[%d].Body type %T", i, refBody)) } } - case btrfsitem.ExtentCSum: + case *btrfsitem.ExtentCSum: // nothing - case btrfsitem.ExtentDataRef: + case *btrfsitem.ExtentDataRef: o.want(ctx, "Extent being referenced", btrfsprim.EXTENT_TREE_OBJECTID, item.Key.ObjectID, @@ -176,7 +176,7 @@ func handleItem(o rebuildCallbacks, ctx context.Context, treeID btrfsprim.ObjID, body.ObjectID, btrfsitem.EXTENT_DATA_KEY, uint64(body.Offset)) - case btrfsitem.FileExtent: + case *btrfsitem.FileExtent: o.wantOff(ctx, "containing Inode", treeID, item.Key.ObjectID, @@ -194,19 +194,19 @@ func handleItem(o rebuildCallbacks, ctx context.Context, treeID btrfsprim.ObjID, default: o.fsErr(ctx, fmt.Errorf("FileExtent: unexpected body.Type=%v", body.Type)) } - case btrfsitem.FreeSpaceBitmap: + case *btrfsitem.FreeSpaceBitmap: o.wantOff(ctx, "FreeSpaceInfo", treeID, item.Key.ObjectID, btrfsitem.FREE_SPACE_INFO_KEY, item.Key.Offset) - case btrfsitem.FreeSpaceHeader: + case *btrfsitem.FreeSpaceHeader: o.wantOff(ctx, ".Location", treeID, body.Location.ObjectID, body.Location.ItemType, body.Location.Offset) - case btrfsitem.FreeSpaceInfo: + case *btrfsitem.FreeSpaceInfo: if body.Flags.Has(btrfsitem.FREE_SPACE_USING_BITMAPS) { o.wantOff(ctx, "FreeSpaceBitmap", treeID, @@ -214,7 +214,7 @@ func handleItem(o rebuildCallbacks, ctx context.Context, treeID btrfsprim.ObjID, btrfsitem.FREE_SPACE_BITMAP_KEY, item.Key.Offset) } - case btrfsitem.Inode: + case *btrfsitem.Inode: o.want(ctx, "backrefs", treeID, // TODO: validate the number of these against body.NLink item.Key.ObjectID, @@ -227,7 +227,7 @@ func handleItem(o rebuildCallbacks, ctx context.Context, treeID btrfsprim.ObjID, body.BlockGroup, btrfsitem.BLOCK_GROUP_ITEM_KEY) } - case btrfsitem.InodeRefs: + case *btrfsitem.InodeRefs: o.wantOff(ctx, "child Inode", treeID, item.Key.ObjectID, @@ -238,7 +238,7 @@ func handleItem(o rebuildCallbacks, ctx context.Context, treeID btrfsprim.ObjID, btrfsprim.ObjID(item.Key.Offset), btrfsitem.INODE_ITEM_KEY, 0) - for _, ref := range body { + for _, ref := range body.Refs { o.wantOff(ctx, "DIR_ITEM", treeID, btrfsprim.ObjID(item.Key.Offset), @@ -250,12 +250,12 @@ func handleItem(o rebuildCallbacks, ctx context.Context, treeID btrfsprim.ObjID, btrfsitem.DIR_INDEX_KEY, uint64(ref.Index)) } - case btrfsitem.Metadata: + case *btrfsitem.Metadata: for i, ref := range body.Refs { switch refBody := ref.Body.(type) { case nil: // nothing - case btrfsitem.ExtentDataRef: + case *btrfsitem.ExtentDataRef: o.wantOff(ctx, "referencing INode", refBody.Root, refBody.ObjectID, @@ -266,7 +266,7 @@ func handleItem(o rebuildCallbacks, ctx context.Context, treeID btrfsprim.ObjID, refBody.ObjectID, btrfsitem.EXTENT_DATA_KEY, uint64(refBody.Offset)) - case btrfsitem.SharedDataRef: + case *btrfsitem.SharedDataRef: // nothing default: // This is a panic because the item decoder should not emit a new @@ -274,7 +274,7 @@ func handleItem(o rebuildCallbacks, ctx context.Context, treeID btrfsprim.ObjID, panic(fmt.Errorf("should not happen: Metadata: unexpected .Refs[%d].Body type %T", i, refBody)) } } - case btrfsitem.Root: + case *btrfsitem.Root: if body.RootDirID != 0 { o.wantOff(ctx, "root directory", item.Key.ObjectID, @@ -298,7 +298,7 @@ func handleItem(o rebuildCallbacks, ctx context.Context, treeID btrfsprim.ObjID, key.ItemType, key.Offset) } - case btrfsitem.RootRef: + case *btrfsitem.RootRef: var otherType btrfsprim.ItemType var parent, child btrfsprim.ObjID switch item.Key.ItemType { @@ -347,17 +347,17 @@ func handleItem(o rebuildCallbacks, ctx context.Context, treeID btrfsprim.ObjID, treeID, child, btrfsitem.ROOT_ITEM_KEY) - case btrfsitem.SharedDataRef: + case *btrfsitem.SharedDataRef: o.want(ctx, "Extent", btrfsprim.EXTENT_TREE_OBJECTID, item.Key.ObjectID, btrfsitem.EXTENT_ITEM_KEY) - case btrfsitem.UUIDMap: + case *btrfsitem.UUIDMap: o.want(ctx, "subvolume Root", btrfsprim.ROOT_TREE_OBJECTID, body.ObjID, btrfsitem.ROOT_ITEM_KEY) - case btrfsitem.Error: + case *btrfsitem.Error: o.fsErr(ctx, fmt.Errorf("error decoding item: %w", body.Err)) default: // This is a panic because the item decoder should not emit new types without this diff --git a/lib/btrfsprogs/btrfsinspect/scandevices.go b/lib/btrfsprogs/btrfsinspect/scandevices.go index 9b8360c..91b5136 100644 --- a/lib/btrfsprogs/btrfsinspect/scandevices.go +++ b/lib/btrfsprogs/btrfsinspect/scandevices.go @@ -183,14 +183,14 @@ func ScanOneDevice(ctx context.Context, dev *btrfs.Device, sb btrfstree.Superblo switch item.Key.ItemType { case btrfsitem.CHUNK_ITEM_KEY: switch itemBody := item.Body.(type) { - case btrfsitem.Chunk: + case *btrfsitem.Chunk: dlog.Tracef(ctx, "node@%v: item %v: found chunk", nodeRef.Addr, i) result.FoundChunks = append(result.FoundChunks, btrfstree.SysChunk{ Key: item.Key, - Chunk: itemBody, + Chunk: *itemBody, }) - case btrfsitem.Error: + case *btrfsitem.Error: dlog.Errorf(ctx, "node@%v: item %v: error: malformed CHUNK_ITEM: %v", nodeRef.Addr, i, itemBody.Err) default: @@ -198,14 +198,14 @@ func ScanOneDevice(ctx context.Context, dev *btrfs.Device, sb btrfstree.Superblo } case btrfsitem.BLOCK_GROUP_ITEM_KEY: switch itemBody := item.Body.(type) { - case btrfsitem.BlockGroup: + case *btrfsitem.BlockGroup: dlog.Tracef(ctx, "node@%v: item %v: found block group", nodeRef.Addr, i) result.FoundBlockGroups = append(result.FoundBlockGroups, SysBlockGroup{ Key: item.Key, - BG: itemBody, + BG: *itemBody, }) - case btrfsitem.Error: + case *btrfsitem.Error: dlog.Errorf(ctx, "node@%v: item %v: error: malformed BLOCK_GROUP_ITEM: %v", nodeRef.Addr, i, itemBody.Err) default: @@ -213,14 +213,14 @@ func ScanOneDevice(ctx context.Context, dev *btrfs.Device, sb btrfstree.Superblo } case btrfsitem.DEV_EXTENT_KEY: switch itemBody := item.Body.(type) { - case btrfsitem.DevExtent: + case *btrfsitem.DevExtent: dlog.Tracef(ctx, "node@%v: item %v: found dev extent", nodeRef.Addr, i) result.FoundDevExtents = append(result.FoundDevExtents, SysDevExtent{ Key: item.Key, - DevExt: itemBody, + DevExt: *itemBody, }) - case btrfsitem.Error: + case *btrfsitem.Error: dlog.Errorf(ctx, "node@%v: item %v: error: malformed DEV_EXTENT: %v", nodeRef.Addr, i, itemBody.Err) default: @@ -228,14 +228,14 @@ func ScanOneDevice(ctx context.Context, dev *btrfs.Device, sb btrfstree.Superblo } case btrfsitem.EXTENT_CSUM_KEY: switch itemBody := item.Body.(type) { - case btrfsitem.ExtentCSum: + case *btrfsitem.ExtentCSum: dlog.Tracef(ctx, "node@%v: item %v: found csums", nodeRef.Addr, i) result.FoundExtentCSums = append(result.FoundExtentCSums, SysExtentCSum{ Generation: nodeRef.Data.Head.Generation, - Sums: itemBody, + Sums: *itemBody, }) - case btrfsitem.Error: + case *btrfsitem.Error: dlog.Errorf(ctx, "node@%v: item %v: error: malformed is EXTENT_CSUM: %v", nodeRef.Addr, i, itemBody.Err) default: -- cgit v1.2.3-54-g00ecf From f76faa4b8debd9c94751a03dd65e46c80a340a82 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Fri, 3 Feb 2023 14:22:02 -0700 Subject: btrfstree: Add a FreeNodeRef function, use it --- lib/btrfs/btrfstree/ops.go | 49 +++++++++++++++++++--- lib/btrfs/btrfstree/types_node.go | 40 ++++++++++++++++-- .../btrfsinspect/rebuildnodes/keyio/keyio.go | 3 ++ lib/btrfsprogs/btrfsinspect/rebuildnodes/scan.go | 5 ++- lib/btrfsprogs/btrfsinspect/scandevices.go | 1 + lib/btrfsprogs/btrfsutil/broken_btree.go | 9 ++++ lib/btrfsprogs/btrfsutil/skinny_paths.go | 1 + 7 files changed, 99 insertions(+), 9 deletions(-) (limited to 'lib/btrfsprogs/btrfsinspect/rebuildnodes/keyio/keyio.go') diff --git a/lib/btrfs/btrfstree/ops.go b/lib/btrfs/btrfstree/ops.go index bda4ac8..b01312f 100644 --- a/lib/btrfs/btrfstree/ops.go +++ b/lib/btrfs/btrfstree/ops.go @@ -144,6 +144,7 @@ func (fs TreeOperatorImpl) treeWalk(ctx context.Context, path TreePath, errHandl } } node, err := fs.ReadNode(path) + defer FreeNodeRef(node) if ctx.Err() != nil { return } @@ -255,6 +256,7 @@ func (fs TreeOperatorImpl) treeSearch(treeRoot TreeRoot, fn func(btrfsprim.Key, } node, err := fs.ReadNode(path) if err != nil { + FreeNodeRef(node) return nil, nil, err } @@ -273,6 +275,7 @@ func (fs TreeOperatorImpl) treeSearch(treeRoot TreeRoot, fn func(btrfsprim.Key, return slices.Min(fn(kp.Key, math.MaxUint32), 0) // don't return >0; a key can't be "too low" }) if !ok { + FreeNodeRef(node) return nil, nil, iofs.ErrNotExist } toMaxKey := path.Node(-1).ToMaxKey @@ -288,6 +291,7 @@ func (fs TreeOperatorImpl) treeSearch(treeRoot TreeRoot, fn func(btrfsprim.Key, ToKey: node.Data.BodyInternal[lastGood].Key, ToMaxKey: toMaxKey, }) + FreeNodeRef(node) } else { // leaf node @@ -305,6 +309,7 @@ func (fs TreeOperatorImpl) treeSearch(treeRoot TreeRoot, fn func(btrfsprim.Key, return fn(item.Key, item.BodySize) }) if !ok { + FreeNodeRef(node) return nil, nil, iofs.ErrNotExist } path = append(path, TreePathElem{ @@ -333,8 +338,10 @@ func (fs TreeOperatorImpl) prev(path TreePath, node *diskio.Ref[btrfsvol.Logical path.Node(-1).FromItemIdx-- if path.Node(-1).ToNodeAddr != 0 { if node.Addr != path.Node(-2).ToNodeAddr { + FreeNodeRef(node) node, err = fs.ReadNode(path.Parent()) if err != nil { + FreeNodeRef(node) return nil, nil, err } path.Node(-1).ToNodeAddr = node.Data.BodyInternal[path.Node(-1).FromItemIdx].BlockPtr @@ -343,8 +350,10 @@ func (fs TreeOperatorImpl) prev(path TreePath, node *diskio.Ref[btrfsvol.Logical // go down for path.Node(-1).ToNodeAddr != 0 { if node.Addr != path.Node(-1).ToNodeAddr { + FreeNodeRef(node) node, err = fs.ReadNode(path) if err != nil { + FreeNodeRef(node) return nil, nil, err } } @@ -369,8 +378,10 @@ func (fs TreeOperatorImpl) prev(path TreePath, node *diskio.Ref[btrfsvol.Logical } // return if node.Addr != path.Node(-2).ToNodeAddr { + FreeNodeRef(node) node, err = fs.ReadNode(path.Parent()) if err != nil { + FreeNodeRef(node) return nil, nil, err } } @@ -383,8 +394,10 @@ func (fs TreeOperatorImpl) next(path TreePath, node *diskio.Ref[btrfsvol.Logical // go up if node.Addr != path.Node(-2).ToNodeAddr { + FreeNodeRef(node) node, err = fs.ReadNode(path.Parent()) if err != nil { + FreeNodeRef(node) return nil, nil, err } path.Node(-2).ToNodeLevel = node.Data.Head.Level @@ -395,8 +408,10 @@ func (fs TreeOperatorImpl) next(path TreePath, node *diskio.Ref[btrfsvol.Logical return nil, nil, nil } if node.Addr != path.Node(-2).ToNodeAddr { + FreeNodeRef(node) node, err = fs.ReadNode(path.Parent()) if err != nil { + FreeNodeRef(node) return nil, nil, err } path.Node(-2).ToNodeLevel = node.Data.Head.Level @@ -406,8 +421,10 @@ func (fs TreeOperatorImpl) next(path TreePath, node *diskio.Ref[btrfsvol.Logical path.Node(-1).FromItemIdx++ if path.Node(-1).ToNodeAddr != 0 { if node.Addr != path.Node(-2).ToNodeAddr { + FreeNodeRef(node) node, err = fs.ReadNode(path.Parent()) if err != nil { + FreeNodeRef(node) return nil, nil, err } path.Node(-1).ToNodeAddr = node.Data.BodyInternal[path.Node(-1).FromItemIdx].BlockPtr @@ -416,8 +433,10 @@ func (fs TreeOperatorImpl) next(path TreePath, node *diskio.Ref[btrfsvol.Logical // go down for path.Node(-1).ToNodeAddr != 0 { if node.Addr != path.Node(-1).ToNodeAddr { + FreeNodeRef(node) node, err = fs.ReadNode(path) if err != nil { + FreeNodeRef(node) return nil, nil, err } path.Node(-1).ToNodeLevel = node.Data.Head.Level @@ -447,8 +466,10 @@ func (fs TreeOperatorImpl) next(path TreePath, node *diskio.Ref[btrfsvol.Logical } // return if node.Addr != path.Node(-2).ToNodeAddr { + FreeNodeRef(node) node, err = fs.ReadNode(path.Parent()) if err != nil { + FreeNodeRef(node) return nil, nil, err } } @@ -469,7 +490,10 @@ func (fs TreeOperatorImpl) TreeSearch(treeID btrfsprim.ObjID, fn func(btrfsprim. if err != nil { return Item{}, err } - return node.Data.BodyLeaf[path.Node(-1).FromItemIdx], nil + item := node.Data.BodyLeaf[path.Node(-1).FromItemIdx] + item.Body = item.Body.CloneItem() + FreeNodeRef(node) + return item, nil } // KeySearch returns a comparator suitable to be passed to TreeSearch. @@ -506,7 +530,8 @@ func (fs TreeOperatorImpl) TreeSearchAll(treeID btrfsprim.ObjID, fn func(btrfspr ret := []Item{middleItem} var errs derror.MultiError - for prevPath, prevNode := middlePath, middleNode; true; { + prevPath, prevNode := middlePath, middleNode + for { prevPath, prevNode, err = fs.prev(prevPath, prevNode) if err != nil { errs = append(errs, err) @@ -519,10 +544,21 @@ func (fs TreeOperatorImpl) TreeSearchAll(treeID btrfsprim.ObjID, fn func(btrfspr if fn(prevItem.Key, prevItem.BodySize) != 0 { break } - ret = append(ret, prevItem) + item := prevItem + item.Body = item.Body.CloneItem() + ret = append(ret, item) } slices.Reverse(ret) - for nextPath, nextNode := middlePath, middleNode; true; { + if prevNode.Addr != middlePath.Node(-1).ToNodeAddr { + FreeNodeRef(prevNode) + middleNode, err = fs.ReadNode(middlePath) + if err != nil { + FreeNodeRef(middleNode) + return nil, err + } + } + nextPath, nextNode := middlePath, middleNode + for { nextPath, nextNode, err = fs.next(nextPath, nextNode) if err != nil { errs = append(errs, err) @@ -535,8 +571,11 @@ func (fs TreeOperatorImpl) TreeSearchAll(treeID btrfsprim.ObjID, fn func(btrfspr if fn(nextItem.Key, nextItem.BodySize) != 0 { break } - ret = append(ret, nextItem) + item := nextItem + item.Body = item.Body.CloneItem() + ret = append(ret, item) } + FreeNodeRef(nextNode) if errs != nil { err = errs } diff --git a/lib/btrfs/btrfstree/types_node.go b/lib/btrfs/btrfstree/types_node.go index 85aae23..fd4c939 100644 --- a/lib/btrfs/btrfstree/types_node.go +++ b/lib/btrfs/btrfstree/types_node.go @@ -8,7 +8,9 @@ import ( "encoding/binary" "errors" "fmt" + "unsafe" + "git.lukeshu.com/go/typedsync" "github.com/datawire/dlib/derror" "git.lukeshu.com/btrfs-progs-ng/lib/binstruct" @@ -300,12 +302,24 @@ type ItemHeader struct { binstruct.End `bin:"off=0x19"` } +var itemPool containers.SlicePool[Item] + +func (node *Node) Free() { + for i := range node.BodyLeaf { + node.BodyLeaf[i].Body.Free() + node.BodyLeaf[i] = Item{} + } + itemPool.Put(node.BodyLeaf) + *node = Node{} +} + func (node *Node) unmarshalLeaf(bodyBuf []byte) (int, error) { head := 0 tail := len(bodyBuf) - node.BodyLeaf = make([]Item, node.Head.NumItems) + node.BodyLeaf = itemPool.Get(int(node.Head.NumItems)) + var itemHead ItemHeader for i := range node.BodyLeaf { - var itemHead ItemHeader + itemHead = ItemHeader{} // zero it out n, err := binstruct.Unmarshal(bodyBuf[head:], &itemHead) head += n if err != nil { @@ -423,6 +437,25 @@ func (e *IOError) Unwrap() error { return e.Err } var bytePool containers.SlicePool[byte] +var nodePool = typedsync.Pool[*diskio.Ref[int64, Node]]{ + New: func() *diskio.Ref[int64, Node] { + return new(diskio.Ref[int64, Node]) + }, +} + +func FreeNodeRef[Addr ~int64](ref *diskio.Ref[Addr, Node]) { + if ref == nil { + return + } + ref.Data.Free() + nodePool.Put((*diskio.Ref[int64, Node])(unsafe.Pointer(ref))) //nolint:gosec // I know it's unsafe. +} + +func newNodeRef[Addr ~int64]() *diskio.Ref[Addr, Node] { + ret, _ := nodePool.Get() + return (*diskio.Ref[Addr, Node])(unsafe.Pointer(ret)) //nolint:gosec // I know it's unsafe. +} + // It is possible that both a non-nil diskio.Ref and an error are // returned. The error returned (if non-nil) is always of type // *NodeError[Addr]. Notable errors that may be inside of the @@ -443,7 +476,8 @@ func ReadNode[Addr ~int64](fs diskio.File[Addr], sb Superblock, addr Addr, exp N // parse (early) - nodeRef := &diskio.Ref[Addr, Node]{ + nodeRef := newNodeRef[Addr]() + *nodeRef = diskio.Ref[Addr, Node]{ File: fs, Addr: addr, Data: Node{ diff --git a/lib/btrfsprogs/btrfsinspect/rebuildnodes/keyio/keyio.go b/lib/btrfsprogs/btrfsinspect/rebuildnodes/keyio/keyio.go index 149706d..b4ab645 100644 --- a/lib/btrfsprogs/btrfsinspect/rebuildnodes/keyio/keyio.go +++ b/lib/btrfsprogs/btrfsinspect/rebuildnodes/keyio/keyio.go @@ -62,6 +62,9 @@ func NewHandle(file diskio.File[btrfsvol.LogicalAddr], sb btrfstree.Superblock) cache: containers.ARCache[btrfsvol.LogicalAddr, *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.Node]]{ MaxLen: textui.Tunable(8), + OnRemove: func(_ btrfsvol.LogicalAddr, nodeRef *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.Node]) { + btrfstree.FreeNodeRef(nodeRef) + }, }, } } diff --git a/lib/btrfsprogs/btrfsinspect/rebuildnodes/scan.go b/lib/btrfsprogs/btrfsinspect/rebuildnodes/scan.go index 7e19802..632ed70 100644 --- a/lib/btrfsprogs/btrfsinspect/rebuildnodes/scan.go +++ b/lib/btrfsprogs/btrfsinspect/rebuildnodes/scan.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -48,12 +48,15 @@ func ScanDevices(ctx context.Context, fs *btrfs.FS, scanResults btrfsinspect.Sca LAddr: containers.Optional[btrfsvol.LogicalAddr]{OK: true, Val: laddr}, }) if err != nil { + btrfstree.FreeNodeRef(nodeRef) return btrfstree.Superblock{}, graph.Graph{}, nil, err } nodeGraph.InsertNode(nodeRef) keyIO.InsertNode(nodeRef) + btrfstree.FreeNodeRef(nodeRef) + stats.N++ progressWriter.Set(stats) } diff --git a/lib/btrfsprogs/btrfsinspect/scandevices.go b/lib/btrfsprogs/btrfsinspect/scandevices.go index 0cfee5b..d54be71 100644 --- a/lib/btrfsprogs/btrfsinspect/scandevices.go +++ b/lib/btrfsprogs/btrfsinspect/scandevices.go @@ -245,6 +245,7 @@ func ScanOneDevice(ctx context.Context, dev *btrfs.Device, sb btrfstree.Superblo } minNextNode = pos + btrfsvol.PhysicalAddr(sb.NodeSize) } + btrfstree.FreeNodeRef(nodeRef) } } progress(devSize) diff --git a/lib/btrfsprogs/btrfsutil/broken_btree.go b/lib/btrfsprogs/btrfsutil/broken_btree.go index 7ea31ce..15641ab 100644 --- a/lib/btrfsprogs/btrfsutil/broken_btree.go +++ b/lib/btrfsprogs/btrfsutil/broken_btree.go @@ -237,11 +237,13 @@ func (bt *brokenTrees) TreeSearch(treeID btrfsprim.ObjID, fn func(btrfsprim.Key, itemPath := bt.arena.Inflate(indexItem.Value.Path) node, err := bt.inner.ReadNode(itemPath.Parent()) + defer btrfstree.FreeNodeRef(node) if err != nil { return btrfstree.Item{}, bt.addErrs(index, fn, err) } item := node.Data.BodyLeaf[itemPath.Node(-1).FromItemIdx] + item.Body = item.Body.CloneItem() // Since we were only asked to return 1 item, it isn't // necessary to augment this `nil` with bt.addErrs(). @@ -271,13 +273,16 @@ func (bt *brokenTrees) TreeSearchAll(treeID btrfsprim.ObjID, fn func(btrfsprim.K itemPath := bt.arena.Inflate(indexItems[i].Path) if node == nil || node.Addr != itemPath.Node(-2).ToNodeAddr { var err error + btrfstree.FreeNodeRef(node) node, err = bt.inner.ReadNode(itemPath.Parent()) if err != nil { + btrfstree.FreeNodeRef(node) return nil, bt.addErrs(index, fn, err) } } ret[i] = node.Data.BodyLeaf[itemPath.Node(-1).FromItemIdx] } + btrfstree.FreeNodeRef(node) return ret, bt.addErrs(index, fn, nil) } @@ -306,8 +311,10 @@ func (bt *brokenTrees) TreeWalk(ctx context.Context, treeID btrfsprim.ObjID, err itemPath := bt.arena.Inflate(indexItem.Value.Path) if node == nil || node.Addr != itemPath.Node(-2).ToNodeAddr { var err error + btrfstree.FreeNodeRef(node) node, err = bt.inner.ReadNode(itemPath.Parent()) if err != nil { + btrfstree.FreeNodeRef(node) errHandle(&btrfstree.TreeError{Path: itemPath, Err: err}) return true } @@ -319,6 +326,7 @@ func (bt *brokenTrees) TreeWalk(ctx context.Context, treeID btrfsprim.ObjID, err } return true }) + btrfstree.FreeNodeRef(node) } func (bt *brokenTrees) Superblock() (*btrfstree.Superblock, error) { @@ -339,6 +347,7 @@ func (bt *brokenTrees) Augment(treeID btrfsprim.ObjID, nodeAddr btrfsvol.Logical return nil, index.TreeRootErr } nodeRef, err := btrfstree.ReadNode[btrfsvol.LogicalAddr](bt.inner, *sb, nodeAddr, btrfstree.NodeExpectations{}) + defer btrfstree.FreeNodeRef(nodeRef) if err != nil { return nil, err } diff --git a/lib/btrfsprogs/btrfsutil/skinny_paths.go b/lib/btrfsprogs/btrfsutil/skinny_paths.go index 4c314ec..1695990 100644 --- a/lib/btrfsprogs/btrfsutil/skinny_paths.go +++ b/lib/btrfsprogs/btrfsutil/skinny_paths.go @@ -55,6 +55,7 @@ func (a *SkinnyPathArena) getItem(parent btrfstree.TreePath, itemIdx int) (btrfs } node, err := btrfstree.ReadNode(a.FS, a.SB, parent.Node(-1).ToNodeAddr, btrfstree.NodeExpectations{}) + defer btrfstree.FreeNodeRef(node) if err != nil { return btrfstree.TreePathElem{}, err } -- cgit v1.2.3-54-g00ecf