diff options
Diffstat (limited to 'lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuild_graph.go')
-rw-r--r-- | lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuild_graph.go | 367 |
1 files changed, 0 insertions, 367 deletions
diff --git a/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuild_graph.go b/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuild_graph.go deleted file mode 100644 index 710030c..0000000 --- a/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuild_graph.go +++ /dev/null @@ -1,367 +0,0 @@ -// Copyright (C) 2022-2023 Luke Shumaker <lukeshu@lukeshu.com> -// -// SPDX-License-Identifier: GPL-2.0-or-later - -package rebuildnodes - -import ( - "context" - "fmt" - - "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsitem" - "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsprim" - "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfstree" - "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol" -) - -type rebuildCallbacks interface { - fsErr(ctx context.Context, e error) - want(ctx context.Context, reason string, treeID btrfsprim.ObjID, objID btrfsprim.ObjID, typ btrfsprim.ItemType) - wantOff(ctx context.Context, reason string, treeID btrfsprim.ObjID, objID btrfsprim.ObjID, typ btrfsprim.ItemType, off uint64) - wantDirIndex(ctx context.Context, reason string, treeID btrfsprim.ObjID, objID btrfsprim.ObjID, name []byte) - wantCSum(ctx context.Context, reason string, inodeTree, inodeItem btrfsprim.ObjID, beg, end btrfsvol.LogicalAddr) // interval is [beg, end) - wantFileExt(ctx context.Context, reason string, treeID btrfsprim.ObjID, ino btrfsprim.ObjID, size int64) -} - -// handleWouldBeNoOp returns whether or not a call to handleItem for a -// given item type would be a no-op. -func handleWouldBeNoOp(typ btrfsprim.ItemType) bool { - switch typ { - case // btrfsitem.Dev - btrfsprim.DEV_ITEM_KEY, - // btrfsitem.DevStats - btrfsprim.PERSISTENT_ITEM_KEY, - // btrfsitem.Empty - btrfsprim.ORPHAN_ITEM_KEY, - btrfsprim.TREE_BLOCK_REF_KEY, - btrfsprim.SHARED_BLOCK_REF_KEY, - btrfsprim.FREE_SPACE_EXTENT_KEY, - btrfsprim.QGROUP_RELATION_KEY, - // btrfsite.ExtentCSum - btrfsprim.EXTENT_CSUM_KEY: - return true - default: - return false - } -} - -func handleItem(o rebuildCallbacks, ctx context.Context, treeID btrfsprim.ObjID, item btrfstree.Item) { - // Notionally, just express the relationships shown in - // 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: - o.want(ctx, "Chunk", - btrfsprim.CHUNK_TREE_OBJECTID, - body.ChunkObjectID, - btrfsitem.CHUNK_ITEM_KEY) - o.wantOff(ctx, "FreeSpaceInfo", - btrfsprim.FREE_SPACE_TREE_OBJECTID, - item.Key.ObjectID, - btrfsitem.FREE_SPACE_INFO_KEY, - item.Key.Offset) - case *btrfsitem.Chunk: - o.want(ctx, "owning Root", - btrfsprim.ROOT_TREE_OBJECTID, - body.Head.Owner, - btrfsitem.ROOT_ITEM_KEY) - case *btrfsitem.Dev: - // nothing - case *btrfsitem.DevExtent: - o.wantOff(ctx, "Chunk", - body.ChunkTree, - body.ChunkObjectID, - btrfsitem.CHUNK_ITEM_KEY, - uint64(body.ChunkOffset)) - case *btrfsitem.DevStats: - // nothing - case *btrfsitem.DirEntry: - // containing-directory - o.wantOff(ctx, "containing dir inode", - treeID, - item.Key.ObjectID, - btrfsitem.INODE_ITEM_KEY, - 0) - // siblings - switch item.Key.ItemType { - case btrfsitem.DIR_ITEM_KEY: - o.wantDirIndex(ctx, "corresponding DIR_INDEX", - treeID, - item.Key.ObjectID, - body.Name) - case btrfsitem.DIR_INDEX_KEY: - o.wantOff(ctx, "corresponding DIR_ITEM", - treeID, - item.Key.ObjectID, - btrfsitem.DIR_ITEM_KEY, - btrfsitem.NameHash(body.Name)) - case btrfsitem.XATTR_ITEM_KEY: - // nothing - default: - // This is a panic because the item decoder should not emit a - // btrfsitem.DirEntry for other item types without this code also being - // updated. - panic(fmt.Errorf("should not happen: DirEntry: unexpected ItemType=%v", item.Key.ItemType)) - } - // item-within-directory - if body.Location != (btrfsprim.Key{}) { - switch body.Location.ItemType { - case btrfsitem.INODE_ITEM_KEY: - o.wantOff(ctx, "item being pointed to", - treeID, - body.Location.ObjectID, - body.Location.ItemType, - body.Location.Offset) - o.wantOff(ctx, "backref from item being pointed to", - treeID, - body.Location.ObjectID, - btrfsitem.INODE_REF_KEY, - uint64(item.Key.ObjectID)) - case btrfsitem.ROOT_ITEM_KEY: - o.want(ctx, "Root of subvolume being pointed to", - btrfsprim.ROOT_TREE_OBJECTID, - body.Location.ObjectID, - body.Location.ItemType) - default: - o.fsErr(ctx, fmt.Errorf("DirEntry: unexpected .Location.ItemType=%v", body.Location.ItemType)) - } - } - case *btrfsitem.Empty: - // nothing - 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 - // // first key in the node. But nothing in the - // // kernel ever reads this, so who knows if it - // // always gets updated correctly? - // } - for i, ref := range body.Refs { - switch refBody := ref.Body.(type) { - case nil: - // nothing - case *btrfsitem.ExtentDataRef: - o.wantOff(ctx, "referencing Inode", - refBody.Root, - refBody.ObjectID, - btrfsitem.INODE_ITEM_KEY, - 0) - o.wantOff(ctx, "referencing FileExtent", - refBody.Root, - refBody.ObjectID, - btrfsitem.EXTENT_DATA_KEY, - uint64(refBody.Offset)) - case *btrfsitem.SharedDataRef: - // nothing - default: - // This is a panic because the item decoder should not emit a new - // type to ref.Body without this code also being updated. - panic(fmt.Errorf("should not happen: Extent: unexpected .Refs[%d].Body type %T", i, refBody)) - } - } - case *btrfsitem.ExtentCSum: - // nothing - case *btrfsitem.ExtentDataRef: - o.want(ctx, "Extent being referenced", - btrfsprim.EXTENT_TREE_OBJECTID, - item.Key.ObjectID, - btrfsitem.EXTENT_ITEM_KEY) - o.wantOff(ctx, "referencing Inode", - body.Root, - body.ObjectID, - btrfsitem.INODE_ITEM_KEY, - 0) - o.wantOff(ctx, "referencing FileExtent", - body.Root, - body.ObjectID, - btrfsitem.EXTENT_DATA_KEY, - uint64(body.Offset)) - case *btrfsitem.FileExtent: - o.wantOff(ctx, "containing Inode", - treeID, - item.Key.ObjectID, - btrfsitem.INODE_ITEM_KEY, - 0) - switch body.Type { - case btrfsitem.FILE_EXTENT_INLINE: - // nothing - case btrfsitem.FILE_EXTENT_REG, btrfsitem.FILE_EXTENT_PREALLOC: - // NB: o.wantCSum checks inodeBody.Flags.Has(btrfsitem.INODE_NODATASUM) for us. - o.wantCSum(ctx, "data sum", - treeID, item.Key.ObjectID, - body.BodyExtent.DiskByteNr, - body.BodyExtent.DiskByteNr.Add(body.BodyExtent.DiskNumBytes)) - default: - o.fsErr(ctx, fmt.Errorf("FileExtent: unexpected body.Type=%v", body.Type)) - } - case *btrfsitem.FreeSpaceBitmap: - o.wantOff(ctx, "FreeSpaceInfo", - treeID, - item.Key.ObjectID, - btrfsitem.FREE_SPACE_INFO_KEY, - item.Key.Offset) - case *btrfsitem.FreeSpaceHeader: - o.wantOff(ctx, ".Location", - treeID, - body.Location.ObjectID, - body.Location.ItemType, - body.Location.Offset) - case *btrfsitem.FreeSpaceInfo: - if body.Flags.Has(btrfsitem.FREE_SPACE_USING_BITMAPS) { - o.wantOff(ctx, "FreeSpaceBitmap", - treeID, - item.Key.ObjectID, - btrfsitem.FREE_SPACE_BITMAP_KEY, - item.Key.Offset) - } - case *btrfsitem.Inode: - o.want(ctx, "backrefs", - treeID, // TODO: validate the number of these against body.NLink - item.Key.ObjectID, - btrfsitem.INODE_REF_KEY) - o.wantFileExt(ctx, "FileExtents", - treeID, item.Key.ObjectID, body.Size) - if body.BlockGroup != 0 { - o.want(ctx, "BlockGroup", - btrfsprim.EXTENT_TREE_OBJECTID, - body.BlockGroup, - btrfsitem.BLOCK_GROUP_ITEM_KEY) - } - case *btrfsitem.InodeRefs: - o.wantOff(ctx, "child Inode", - treeID, - item.Key.ObjectID, - btrfsitem.INODE_ITEM_KEY, - 0) - o.wantOff(ctx, "parent Inode", - treeID, - btrfsprim.ObjID(item.Key.Offset), - btrfsitem.INODE_ITEM_KEY, - 0) - for _, ref := range body.Refs { - o.wantOff(ctx, "DIR_ITEM", - treeID, - btrfsprim.ObjID(item.Key.Offset), - btrfsitem.DIR_ITEM_KEY, - btrfsitem.NameHash(ref.Name)) - o.wantOff(ctx, "DIR_INDEX", - treeID, - btrfsprim.ObjID(item.Key.Offset), - btrfsitem.DIR_INDEX_KEY, - uint64(ref.Index)) - } - case *btrfsitem.Metadata: - for i, ref := range body.Refs { - switch refBody := ref.Body.(type) { - case nil: - // nothing - case *btrfsitem.ExtentDataRef: - o.wantOff(ctx, "referencing INode", - refBody.Root, - refBody.ObjectID, - btrfsitem.INODE_ITEM_KEY, - 0) - o.wantOff(ctx, "referencing FileExtent", - refBody.Root, - refBody.ObjectID, - btrfsitem.EXTENT_DATA_KEY, - uint64(refBody.Offset)) - case *btrfsitem.SharedDataRef: - // nothing - default: - // This is a panic because the item decoder should not emit a new - // type to ref.Body without this code also being updated. - panic(fmt.Errorf("should not happen: Metadata: unexpected .Refs[%d].Body type %T", i, refBody)) - } - } - case *btrfsitem.Root: - if body.RootDirID != 0 { - o.wantOff(ctx, "root directory", - item.Key.ObjectID, - body.RootDirID, - btrfsitem.INODE_ITEM_KEY, - 0) - } - if body.UUID != (btrfsprim.UUID{}) { - key := btrfsitem.UUIDToKey(body.UUID) - o.wantOff(ctx, "uuid", - btrfsprim.UUID_TREE_OBJECTID, - key.ObjectID, - key.ItemType, - key.Offset) - } - if body.ParentUUID != (btrfsprim.UUID{}) { - key := btrfsitem.UUIDToKey(body.ParentUUID) - o.wantOff(ctx, "parent uuid", - btrfsprim.UUID_TREE_OBJECTID, - key.ObjectID, - key.ItemType, - key.Offset) - } - case *btrfsitem.RootRef: - var otherType btrfsprim.ItemType - var parent, child btrfsprim.ObjID - switch item.Key.ItemType { - case btrfsitem.ROOT_REF_KEY: - otherType = btrfsitem.ROOT_BACKREF_KEY - parent = item.Key.ObjectID - child = btrfsprim.ObjID(item.Key.Offset) - case btrfsitem.ROOT_BACKREF_KEY: - otherType = btrfsitem.ROOT_REF_KEY - parent = btrfsprim.ObjID(item.Key.Offset) - child = item.Key.ObjectID - default: - // This is a panic because the item decoder should not emit a - // btrfsitem.RootRef for other item types without this code also being - // updated. - panic(fmt.Errorf("should not happen: RootRef: unexpected ItemType=%v", item.Key.ItemType)) - } - // sibling - o.wantOff(ctx, fmt.Sprintf("corresponding %v", otherType), - treeID, - btrfsprim.ObjID(item.Key.Offset), - otherType, - uint64(item.Key.ObjectID)) - // parent - o.want(ctx, "parent subvolume: Root", - treeID, - parent, - btrfsitem.ROOT_ITEM_KEY) - o.wantOff(ctx, "parent subvolume: Inode of parent dir", - parent, - body.DirID, - btrfsitem.INODE_ITEM_KEY, - 0) - o.wantOff(ctx, "parent subvolume: DIR_ITEM in parent dir", - parent, - body.DirID, - btrfsitem.DIR_ITEM_KEY, - btrfsitem.NameHash(body.Name)) - o.wantOff(ctx, "parent subvolume: DIR_INDEX in parent dir", - parent, - body.DirID, - btrfsitem.DIR_INDEX_KEY, - uint64(body.Sequence)) - // child - o.want(ctx, "child subvolume: Root", - treeID, - child, - btrfsitem.ROOT_ITEM_KEY) - case *btrfsitem.SharedDataRef: - o.want(ctx, "Extent", - btrfsprim.EXTENT_TREE_OBJECTID, - item.Key.ObjectID, - btrfsitem.EXTENT_ITEM_KEY) - case *btrfsitem.UUIDMap: - o.want(ctx, "subvolume Root", - btrfsprim.ROOT_TREE_OBJECTID, - body.ObjID, - btrfsitem.ROOT_ITEM_KEY) - 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 - // code also being updated. - panic(fmt.Errorf("should not happen: unexpected item type: %T", body)) - } -} |