diff options
Diffstat (limited to 'lib/btrfs')
32 files changed, 263 insertions, 95 deletions
diff --git a/lib/btrfs/btrfsitem/item_blockgroup.go b/lib/btrfs/btrfsitem/item_blockgroup.go index ae0ca12..dc561bd 100644 --- a/lib/btrfs/btrfsitem/item_blockgroup.go +++ b/lib/btrfs/btrfsitem/item_blockgroup.go @@ -10,8 +10,20 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol" ) -// key.objectid = logical_addr -// key.offset = size of chunk +// A BlockGroup tracks allocation of the logical address space. +// +// Compare with: +// - DevExtents, which track allocation of the physical address space. +// - Chunks, which map logical addresses to physical addresses. +// +// The relationship between the three is +// +// DevExtent---[many:one]---Chunk---[one:one]---BlockGroup +// +// Key: +// +// key.objectid = logical_addr +// key.offset = size of chunk type BlockGroup struct { // trivial BLOCK_GROUP_ITEM=192 Used int64 `bin:"off=0, siz=8"` ChunkObjectID btrfsprim.ObjID `bin:"off=8, siz=8"` // always FIRST_CHUNK_TREE_OBJECTID diff --git a/lib/btrfs/btrfsitem/item_chunk.go b/lib/btrfs/btrfsitem/item_chunk.go index 2280a0b..607df75 100644 --- a/lib/btrfs/btrfsitem/item_chunk.go +++ b/lib/btrfs/btrfsitem/item_chunk.go @@ -11,10 +11,20 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/containers" ) -// Maps logical address to physical. +// A Chunk maps logical addresses to physical addresses. // -// key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID -// key.offset = logical_addr +// Compare with: +// - DevExtents, which track allocation of the physical address space. +// - BlockGroups, which track allocation of the logical address space. +// +// The relationship between the three is +// +// DevExtent---[many:one]---Chunk---[one:one]---BlockGroup +// +// Key: +// +// key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID +// key.offset = logical_addr type Chunk struct { // complex CHUNK_ITEM=228 Head ChunkHeader Stripes []ChunkStripe diff --git a/lib/btrfs/btrfsitem/item_dev.go b/lib/btrfs/btrfsitem/item_dev.go index 188711e..7fd6833 100644 --- a/lib/btrfs/btrfsitem/item_dev.go +++ b/lib/btrfs/btrfsitem/item_dev.go @@ -10,8 +10,12 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol" ) -// key.objectid = BTRFS_DEV_ITEMS_OBJECTID -// key.offset = device_id (starting at 1) +// A Dev describes a physical volume that is part of the filesystem. +// +// Key: +// +// key.objectid = BTRFS_DEV_ITEMS_OBJECTID +// key.offset = device_id (starting at 1) type Dev struct { // trivial DEV_ITEM=216 DevID btrfsvol.DeviceID `bin:"off=0x0, siz=0x8"` diff --git a/lib/btrfs/btrfsitem/item_devextent.go b/lib/btrfs/btrfsitem/item_devextent.go index cade165..6998277 100644 --- a/lib/btrfs/btrfsitem/item_devextent.go +++ b/lib/btrfs/btrfsitem/item_devextent.go @@ -10,8 +10,23 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol" ) -// key.objectid = device_id -// key.offset = physical_addr +// A DevExtent tracks allocation of the physical address space. +// +// Compare with: +// - BlockGroups, which track allocation of the logical address space. +// - Chunks, which map logical addresses to physical addresses. +// +// The relationship between the three is +// +// DevExtent---[many:one]---Chunk---[one:one]---BlockGroup +// +// The device ID identifies which Dev item describes the physical +// volume that the DevExtent is on. +// +// Key: +// +// key.objectid = device_id +// key.offset = physical_addr type DevExtent struct { // trivial DEV_EXTENT=204 ChunkTree btrfsprim.ObjID `bin:"off=0, siz=8"` // always CHUNK_TREE_OBJECTID ChunkObjectID btrfsprim.ObjID `bin:"off=8, siz=8"` // which chunk within .ChunkTree owns this extent, always FIRST_CHUNK_TREE_OBJECTID diff --git a/lib/btrfs/btrfsitem/item_dir.go b/lib/btrfs/btrfsitem/item_dir.go index c1b3c09..cd16d57 100644 --- a/lib/btrfs/btrfsitem/item_dir.go +++ b/lib/btrfs/btrfsitem/item_dir.go @@ -19,10 +19,14 @@ func NameHash(dat []byte) uint64 { return uint64(^crc32.Update(1, crc32.MakeTable(crc32.Castagnoli), dat)) } -// key.objectid = inode of directory containing this entry -// key.offset = -// - for DIR_ITEM and XATTR_ITEM = NameHash(name) -// - for DIR_INDEX = index id in the directory (starting at 2, because "." and "..") +// A DirEntry is an member of a directory. +// +// Key: +// +// key.objectid = inode of directory containing this entry +// key.offset = one of: +// - for DIR_ITEM and XATTR_ITEM = NameHash(name) +// - for DIR_INDEX = index id in the directory (starting at 2, because of "." and "..") type DirEntry struct { // complex DIR_ITEM=84 DIR_INDEX=96 XATTR_ITEM=24 Location btrfsprim.Key `bin:"off=0x0, siz=0x11"` TransID int64 `bin:"off=0x11, siz=8"` diff --git a/lib/btrfs/btrfsitem/item_extent.go b/lib/btrfs/btrfsitem/item_extent.go index 871ed90..edfef7c 100644 --- a/lib/btrfs/btrfsitem/item_extent.go +++ b/lib/btrfs/btrfsitem/item_extent.go @@ -13,8 +13,22 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/fmtutil" ) -// key.objectid = laddr of the extent -// key.offset = length of the extent +// Extent items map from regions in the logical address space to +// regions in a file. +// +// Compare with: +// +// - Metadata, which are like Extents but without .Info. +// - FileExtents, which map from regions in a file to regions in the +// logical address space. +// +// An Extent may contain (inline or not) several ExtentDataRef items +// and/or ShareDataRef items. +// +// Key: +// +// key.objectid = laddr of the extent +// key.offset = length of the extent type Extent struct { // complex EXTENT_ITEM=168 Head ExtentHeader Info TreeBlockInfo // only if .Head.Flags.Has(EXTENT_FLAG_TREE_BLOCK) diff --git a/lib/btrfs/btrfsitem/item_extentcsum.go b/lib/btrfs/btrfsitem/item_extentcsum.go index dfa166d..a963c16 100644 --- a/lib/btrfs/btrfsitem/item_extentcsum.go +++ b/lib/btrfs/btrfsitem/item_extentcsum.go @@ -11,8 +11,12 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol" ) -// key.objectid = BTRFS_EXTENT_CSUM_OBJECTID -// key.offset = laddr of checksummed region +// An ExtentCSum checksums regions of the logical address space. +// +// Key: +// +// key.objectid = BTRFS_EXTENT_CSUM_OBJECTID +// key.offset = laddr of checksummed region type ExtentCSum struct { // trivial EXTENT_CSUM=128 // Checksum of each sector starting at key.offset btrfssum.SumRun[btrfsvol.LogicalAddr] diff --git a/lib/btrfs/btrfsitem/item_extentdataref.go b/lib/btrfs/btrfsitem/item_extentdataref.go index 6f2257b..bd7bb04 100644 --- a/lib/btrfs/btrfsitem/item_extentdataref.go +++ b/lib/btrfs/btrfsitem/item_extentdataref.go @@ -9,8 +9,12 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsprim" ) -// key.objectid = laddr of the extent being referenced -// key.offset = crc32c([root,objectid,offset]) +// ExtentDataRef is part of an Extent. +// +// Key: +// +// key.objectid = laddr of the extent being referenced +// key.offset = crc32c([root,objectid,offset]) type ExtentDataRef struct { // trivial EXTENT_DATA_REF=178 Root btrfsprim.ObjID `bin:"off=0, siz=8"` // subvolume tree ID that references this extent ObjectID btrfsprim.ObjID `bin:"off=8, siz=8"` // inode number that references this extent within the .Root subvolume diff --git a/lib/btrfs/btrfsitem/item_fileextent.go b/lib/btrfs/btrfsitem/item_fileextent.go index 6b08897..df3d371 100644 --- a/lib/btrfs/btrfsitem/item_fileextent.go +++ b/lib/btrfs/btrfsitem/item_fileextent.go @@ -12,8 +12,19 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol" ) -// key.objectid = inode -// key.offset = offset within file +// FileExtent items map from regions in a file to regions in the +// logical address space. +// +// Compare with: +// +// - Extents, which map from regions in the logical address space to +// regions in a file. +// - Metadata, which are like Extents but without .Info. +// +// Key: +// +// key.objectid = inode +// key.offset = offset within file type FileExtent struct { // complex EXTENT_DATA=108 Generation btrfsprim.Generation `bin:"off=0x0, siz=0x8"` // transaction ID that created this extent RAMBytes int64 `bin:"off=0x8, siz=0x8"` // upper bound of what compressed data will decompress to diff --git a/lib/btrfs/btrfsitem/item_freespacebitmap.go b/lib/btrfs/btrfsitem/item_freespacebitmap.go index ebc00e4..d70a2b5 100644 --- a/lib/btrfs/btrfsitem/item_freespacebitmap.go +++ b/lib/btrfs/btrfsitem/item_freespacebitmap.go @@ -4,8 +4,13 @@ package btrfsitem -// key.objectid = object ID of the FreeSpaceInfo (logical_addr) -// key.offset = offset of the FreeSpaceInfo (size) +// FreeSpaceBitmap is used in conjunction with FreeSpaceInfo for +// highly-fragmented blockgroups. +// +// Key: +// +// key.objectid = object ID of the FreeSpaceInfo (logical_addr) +// key.offset = offset of the FreeSpaceInfo (size) type FreeSpaceBitmap struct { // complex FREE_SPACE_BITMAP=200 Bitmap []byte } diff --git a/lib/btrfs/btrfsitem/item_freespaceinfo.go b/lib/btrfs/btrfsitem/item_freespaceinfo.go index 9b886af..7782d27 100644 --- a/lib/btrfs/btrfsitem/item_freespaceinfo.go +++ b/lib/btrfs/btrfsitem/item_freespaceinfo.go @@ -9,8 +9,14 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/fmtutil" ) -// key.objectid = object ID of the BlockGroup (logical_addr) -// key.offset = offset of the BlockGroup (size) +// FreeSpaceInfo is the main way (v2) that free space is tracked in a +// BlockGroup. For highly-fragmented blockgorups, it may be augmented +// by a FreeSpaceBitmap. +// +// Key: +// +// key.objectid = object ID of the BlockGroup (logical_addr) +// key.offset = offset of the BlockGroup (size) type FreeSpaceInfo struct { // trivial FREE_SPACE_INFO=198 ExtentCount int32 `bin:"off=0, siz=4"` Flags FreeSpaceFlags `bin:"off=4, siz=4"` diff --git a/lib/btrfs/btrfsitem/item_inode.go b/lib/btrfs/btrfsitem/item_inode.go index 6951c76..0b6a1c2 100644 --- a/lib/btrfs/btrfsitem/item_inode.go +++ b/lib/btrfs/btrfsitem/item_inode.go @@ -10,8 +10,10 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/fmtutil" ) -// key.objectid = inode number -// key.offset = 0 +// Inode is a file/dir/whatever in the filesystem. +// +// key.objectid = inode number +// key.offset = 0 type Inode struct { // trivial INODE_ITEM=1 Generation btrfsprim.Generation `bin:"off=0x00, siz=0x08"` TransID int64 `bin:"off=0x08, siz=0x08"` diff --git a/lib/btrfs/btrfsitem/item_inoderef.go b/lib/btrfs/btrfsitem/item_inoderef.go index 074b26d..f38295d 100644 --- a/lib/btrfs/btrfsitem/item_inoderef.go +++ b/lib/btrfs/btrfsitem/item_inoderef.go @@ -12,11 +12,16 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/containers" ) -// key.objectid = inode number of the file -// key.offset = inode number of the parent directory +// An InodeRefs item is a set of back-references that point to a given +// Inode. // -// Might have multiple entries if the same file has multiple hardlinks -// in the same directory. +// Key: +// +// key.objectid = inode number of the file +// key.offset = inode number of the parent directory +// +// There might be multiple back-references in a single InodeRef item +// if the same file has multiple hardlinks in the same directory. type InodeRefs struct { // complex INODE_REF=12 Refs []InodeRef } diff --git a/lib/btrfs/btrfsitem/item_metadata.go b/lib/btrfs/btrfsitem/item_metadata.go index db2315e..10ae994 100644 --- a/lib/btrfs/btrfsitem/item_metadata.go +++ b/lib/btrfs/btrfsitem/item_metadata.go @@ -8,7 +8,22 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/binstruct" ) +// Metadata items map from regions in the logical address space to +// regions in a file. +// // Metadata is like Extent, but doesn't have .Info. +// +// Compare with: +// +// - Extents, which are the same as Metadata, but have an extra +// .Info member. +// - FileExtents, which map from regions in a file to regions in the +// logical address space. +// +// Key: +// +// key.objectid = laddr of the extent +// key.offset = length of the extent type Metadata struct { // complex METADATA_ITEM=169 Head ExtentHeader Refs []ExtentInlineRef diff --git a/lib/btrfs/btrfsitem/item_qgroupinfo.go b/lib/btrfs/btrfsitem/item_qgroupinfo.go index 6699030..2bf38f6 100644 --- a/lib/btrfs/btrfsitem/item_qgroupinfo.go +++ b/lib/btrfs/btrfsitem/item_qgroupinfo.go @@ -9,8 +9,13 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsprim" ) -// key.objectid = 0 -// key.offset = ID of the qgroup +// QGroupInfo tracks the amount of space used by a given qgroup in the +// containing subvolume. +// +// Key: +// +// key.objectid = 0 +// key.offset = ID of the qgroup type QGroupInfo struct { // trivial QGROUP_INFO=242 Generation btrfsprim.Generation `bin:"off=0, siz=8"` ReferencedBytes uint64 `bin:"off=8, siz=8"` diff --git a/lib/btrfs/btrfsitem/item_qgrouplimit.go b/lib/btrfs/btrfsitem/item_qgrouplimit.go index 47f7eca..e303b04 100644 --- a/lib/btrfs/btrfsitem/item_qgrouplimit.go +++ b/lib/btrfs/btrfsitem/item_qgrouplimit.go @@ -34,8 +34,14 @@ func (f QGroupLimitFlags) String() string { return fmtutil.BitfieldString(f, qgroupLimitFlagNames, fmtutil.HexNone) } -// key.objectid = 0 -// key.offset = ID of the qgroup +// QGroupLimit configures the maximum permissible amount of space that +// a given qgroup can consume (tracked in a QGroupInfo item) on the +// containing subvolume. +// +// Key: +// +// key.objectid = 0 +// key.offset = ID of the qgroup type QGroupLimit struct { // trivial QGROUP_LIMIT=244 Flags QGroupLimitFlags `bin:"off=0, siz=8"` MaxReferenced uint64 `bin:"off=8, siz=8"` diff --git a/lib/btrfs/btrfsitem/item_qgroupstatus.go b/lib/btrfs/btrfsitem/item_qgroupstatus.go index 346c913..b140371 100644 --- a/lib/btrfs/btrfsitem/item_qgroupstatus.go +++ b/lib/btrfs/btrfsitem/item_qgroupstatus.go @@ -32,8 +32,14 @@ func (f QGroupStatusFlags) String() string { const QGroupStatusVersion uint64 = 1 -// key.objectid = 0 -// key.offset = 0 +// A QGroupStatus holds the qgroup state of a subvolume (I think that +// implies that the QGroupStatus goes in the subvolume tree that it is +// describing?). +// +// Key: +// +// key.objectid = 0 +// key.offset = 0 type QGroupStatus struct { // trivial QGROUP_STATUS=240 Version uint64 `bin:"off=0, siz=8"` Generation btrfsprim.Generation `bin:"off=8, siz=8"` diff --git a/lib/btrfs/btrfsitem/item_root.go b/lib/btrfs/btrfsitem/item_root.go index d39bd70..4ffad9a 100644 --- a/lib/btrfs/btrfsitem/item_root.go +++ b/lib/btrfs/btrfsitem/item_root.go @@ -11,10 +11,17 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/fmtutil" ) -// key.objectid = tree ID -// key.offset = either -// - 0 if objectid is one of the BTRFS_*_TREE_OBJECTID defines or a non-snapshot volume; or -// - transaction_id of when this snapshot was created +// A Root goes in the ROOT_TREE and defines one of the other trees in +// the filesystem. All trees have a Root item describing them, except +// for the ROOT_TREE, CHUNK_TREE, TREE_LOG, and BLOCK_GROUP_TREE, +// which are defined directly in the superblock. +// +// Key: +// +// key.objectid = tree ID +// key.offset = one of: +// - 0 if objectid is one of the BTRFS_*_TREE_OBJECTID defines or a non-snapshot volume; or +// - transaction_id of when this snapshot was created type Root struct { // trivial ROOT_ITEM=132 Inode Inode `bin:"off=0x000, siz=0xa0"` // ??? Generation btrfsprim.Generation `bin:"off=0x0a0, siz=0x08"` diff --git a/lib/btrfs/btrfsitem/item_rootref.go b/lib/btrfs/btrfsitem/item_rootref.go index 4179890..e40b278 100644 --- a/lib/btrfs/btrfsitem/item_rootref.go +++ b/lib/btrfs/btrfsitem/item_rootref.go @@ -12,10 +12,12 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsprim" ) -// RootRefs link subvolumes parent→child for normal subvolumes and +// A RootRef links subvolumes parent→child for normal subvolumes and // base→snapshot for snapshot subvolumes. BACKREF items go the other // direction; child→parent and snapshot→base. // +// Key: +// // ROOT_REF | ROOT_BACKREF // key.objectid = ID of the parent subvolume | ID of the child subvolume // key.offset = ID of the child subvolume | ID of the parent subvolume diff --git a/lib/btrfs/btrfsitem/item_shareddataref.go b/lib/btrfs/btrfsitem/item_shareddataref.go index 6143a5c..5d88522 100644 --- a/lib/btrfs/btrfsitem/item_shareddataref.go +++ b/lib/btrfs/btrfsitem/item_shareddataref.go @@ -8,10 +8,12 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/binstruct" ) -// key.objectid = laddr of the extent being referenced +// SharedDataRef is part of an Extent. // -// key.offset = laddr of the leaf node containing the FileExtent -// (EXTENT_DATA_KEY) for this reference. +// Key: +// +// key.objectid = laddr of the extent being referenced +// key.offset = laddr of the leaf node containing the FileExtent (EXTENT_DATA_KEY) for this reference. type SharedDataRef struct { // trivial SHARED_DATA_REF=184 Count int32 `bin:"off=0, siz=4"` // reference count binstruct.End `bin:"off=4"` diff --git a/lib/btrfs/btrfsitem/item_uuid.go b/lib/btrfs/btrfsitem/item_uuid.go index fca409d..a5ace33 100644 --- a/lib/btrfs/btrfsitem/item_uuid.go +++ b/lib/btrfs/btrfsitem/item_uuid.go @@ -11,11 +11,16 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsprim" ) -// The Key for this item is a UUID, and the item is a subvolume IDs +// A UUIDMap item goes in the UUID_TREE and maps from a UUID to a +// btrfsprim.ObjID. +// +// The Key for this item is a UUID, and the item is a subvolume ID // that UUID maps to. // -// key.objectid = first half of UUID -// key.offset = second half of UUID +// Key: +// +// key.objectid = first half of UUID +// key.offset = second half of UUID type UUIDMap struct { // trivial UUID_SUBVOL=251 UUID_RECEIVED_SUBVOL=252 ObjID btrfsprim.ObjID `bin:"off=0, siz=8"` binstruct.End `bin:"off=8"` diff --git a/lib/btrfs/btrfsitem/items.go b/lib/btrfs/btrfsitem/items.go index 49d421f..a730447 100644 --- a/lib/btrfs/btrfsitem/items.go +++ b/lib/btrfs/btrfsitem/items.go @@ -2,6 +2,8 @@ // // SPDX-License-Identifier: GPL-2.0-or-later +// Package btrfsitem contains the definitions of all "items" that may +// be stored in a btrfs tree. package btrfsitem import ( @@ -56,7 +58,11 @@ func (o *Error) UnmarshalBinary(dat []byte) (int, error) { return len(dat), nil } -// Rather than returning a separate error value, return an Error item. +// UnmarshalItem consumes the byte slice `dat`, unmarshaling it in to +// the item type specified by `key`. +// +// If there is an error, rather than returning a separate error value, +// return an Error item. func UnmarshalItem(key btrfsprim.Key, csumType btrfssum.CSumType, dat []byte) Item { var gotyp reflect.Type if key.ItemType == UNTYPED_KEY { diff --git a/lib/btrfs/btrfsprim/key.go b/lib/btrfs/btrfsprim/key.go index b07cc8c..5580c52 100644 --- a/lib/btrfs/btrfsprim/key.go +++ b/lib/btrfs/btrfsprim/key.go @@ -21,7 +21,10 @@ type Key struct { const MaxOffset uint64 = math.MaxUint64 -// mimics print-tree.c:btrfs_print_key() +// Format returns a human-friendly string representation of the Key, +// according to which tree it appears in. +// +// The formatting of the key mimics print-tree.c:btrfs_print_key(). func (key Key) Format(tree ObjID) string { switch tree { case UUID_TREE_OBJECTID: @@ -39,12 +42,11 @@ func (key Key) Format(tree ObjID) string { return fmt.Sprintf("(%v %v -1)", key.ObjectID.Format(tree), key.ItemType) - } else { - return fmt.Sprintf("(%v %v %v)", - key.ObjectID.Format(tree), - key.ItemType, - key.Offset) } + return fmt.Sprintf("(%v %v %v)", + key.ObjectID.Format(tree), + key.ItemType, + key.Offset) } } diff --git a/lib/btrfs/btrfsprim/misc.go b/lib/btrfs/btrfsprim/misc.go index 38290d6..43ba306 100644 --- a/lib/btrfs/btrfsprim/misc.go +++ b/lib/btrfs/btrfsprim/misc.go @@ -2,6 +2,8 @@ // // SPDX-License-Identifier: GPL-2.0-or-later +// Package btrfsprim contains primitive btrfs datatypes, that all +// other btrfs sub-packages may make use of. package btrfsprim import ( diff --git a/lib/btrfs/btrfssum/csum.go b/lib/btrfs/btrfssum/csum.go index 157371e..341eade 100644 --- a/lib/btrfs/btrfssum/csum.go +++ b/lib/btrfs/btrfssum/csum.go @@ -2,6 +2,8 @@ // // SPDX-License-Identifier: GPL-2.0-or-later +// Package btrfssum contains the checksum types and algorithms that +// btrfs uses. package btrfssum import ( diff --git a/lib/btrfs/btrfstree/btree.go b/lib/btrfs/btrfstree/btree.go index 4c10ffa..89d4f9d 100644 --- a/lib/btrfs/btrfstree/btree.go +++ b/lib/btrfs/btrfstree/btree.go @@ -2,6 +2,8 @@ // // SPDX-License-Identifier: GPL-2.0-or-later +// Package btrfstree contains core b+-tree implementation and +// interfaces. package btrfstree import ( diff --git a/lib/btrfs/btrfstree/btree_tree.go b/lib/btrfs/btrfstree/btree_tree.go index df58c0c..1e3c789 100644 --- a/lib/btrfs/btrfstree/btree_tree.go +++ b/lib/btrfs/btrfstree/btree_tree.go @@ -188,7 +188,8 @@ func (fs TreeOperatorImpl) treeSearch(treeRoot TreeRoot, fn func(btrfsprim.Key, return nil, nil, err } - if node.Data.Head.Level > 0 { + switch { + case node.Data.Head.Level > 0: // interior node // Search for the right-most node.Data.BodyInterior item for which @@ -220,7 +221,7 @@ func (fs TreeOperatorImpl) treeSearch(treeRoot TreeRoot, fn func(btrfsprim.Key, ToMaxKey: toMaxKey, }) FreeNodeRef(node) - } else { + default: // leaf node // Search for a member of node.Data.BodyLeaf for which diff --git a/lib/btrfs/btrfstree/path.go b/lib/btrfs/btrfstree/path.go index 9b1a5c7..b9ab5bc 100644 --- a/lib/btrfs/btrfstree/path.go +++ b/lib/btrfs/btrfstree/path.go @@ -101,23 +101,22 @@ func (elem TreePathElem) writeNodeTo(w io.Writer) { func (path TreePath) String() string { if len(path) == 0 { return "(empty-path)" + } + var ret strings.Builder + fmt.Fprintf(&ret, "%s->", path[0].FromTree.Format(btrfsprim.ROOT_TREE_OBJECTID)) + if len(path) == 1 && path[0] == (TreePathElem{FromTree: path[0].FromTree, FromItemSlot: -1}) { + ret.WriteString("(empty-path)") } else { - var ret strings.Builder - fmt.Fprintf(&ret, "%s->", path[0].FromTree.Format(btrfsprim.ROOT_TREE_OBJECTID)) - if len(path) == 1 && path[0] == (TreePathElem{FromTree: path[0].FromTree, FromItemSlot: -1}) { - ret.WriteString("(empty-path)") - } else { - path[0].writeNodeTo(&ret) - } - for _, elem := range path[1:] { - fmt.Fprintf(&ret, "[%v]", elem.FromItemSlot) - if elem.ToNodeAddr != 0 { - ret.WriteString("->") - elem.writeNodeTo(&ret) - } + path[0].writeNodeTo(&ret) + } + for _, elem := range path[1:] { + fmt.Fprintf(&ret, "[%v]", elem.FromItemSlot) + if elem.ToNodeAddr != 0 { + ret.WriteString("->") + elem.writeNodeTo(&ret) } - return ret.String() } + return ret.String() } func (path TreePath) DeepCopy() TreePath { @@ -128,9 +127,10 @@ func (path TreePath) Parent() TreePath { return path[:len(path)-1] } -// path.Node(x) is like &path[x], but negative values of x move down -// from the end of path (similar to how lists work in many other -// languages, such as Python). +// Node is returns an element from the path; `path.Node(x)` is like +// `&path[x]`, but negative values of x move down from the end of path +// (similar to how lists work in many other languages, such as +// Python). func (path TreePath) Node(x int) *TreePathElem { if x < 0 { x += len(path) diff --git a/lib/btrfs/btrfstree/types_node.go b/lib/btrfs/btrfstree/types_node.go index 150539d..8295ccb 100644 --- a/lib/btrfs/btrfstree/types_node.go +++ b/lib/btrfs/btrfstree/types_node.go @@ -113,20 +113,22 @@ type NodeHeader struct { // .Head.NumItems. func (node Node) MaxItems() uint32 { bodyBytes := node.Size - uint32(nodeHeaderSize) - if node.Head.Level > 0 { + switch { + case node.Head.Level > 0: return bodyBytes / uint32(keyPointerSize) - } else { + default: return bodyBytes / uint32(itemHeaderSize) } } func (node Node) MinItem() (btrfsprim.Key, bool) { - if node.Head.Level > 0 { + switch { + case node.Head.Level > 0: if len(node.BodyInterior) == 0 { return btrfsprim.Key{}, false } return node.BodyInterior[0].Key, true - } else { + default: if len(node.BodyLeaf) == 0 { return btrfsprim.Key{}, false } @@ -135,12 +137,13 @@ func (node Node) MinItem() (btrfsprim.Key, bool) { } func (node Node) MaxItem() (btrfsprim.Key, bool) { - if node.Head.Level > 0 { + switch { + case node.Head.Level > 0: if len(node.BodyInterior) == 0 { return btrfsprim.Key{}, false } return node.BodyInterior[len(node.BodyInterior)-1].Key, true - } else { + default: if len(node.BodyLeaf) == 0 { return btrfsprim.Key{}, false } @@ -221,15 +224,15 @@ func (node Node) MarshalBinary() ([]byte, error) { buf := make([]byte, node.Size) - if bs, err := binstruct.Marshal(node.Head); err != nil { + bs, err := binstruct.Marshal(node.Head) + if err != nil { return buf, err - } else { - if len(bs) != nodeHeaderSize { - return nil, fmt.Errorf("header is %v bytes but expected %v", - len(bs), nodeHeaderSize) - } - copy(buf, bs) } + if len(bs) != nodeHeaderSize { + return nil, fmt.Errorf("header is %v bytes but expected %v", + len(bs), nodeHeaderSize) + } + copy(buf, bs) if node.Head.Level > 0 { if err := node.marshalInteriorTo(buf[nodeHeaderSize:]); err != nil { @@ -456,6 +459,8 @@ func newNodeRef[Addr ~int64]() *diskio.Ref[Addr, Node] { return (*diskio.Ref[Addr, Node])(unsafe.Pointer(ret)) //nolint:gosec // I know it's unsafe. } +// ReadNode reads a node from the given file. +// // 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 diff --git a/lib/btrfs/btrfsvol/lvm.go b/lib/btrfs/btrfsvol/lvm.go index 51e2263..3834345 100644 --- a/lib/btrfs/btrfsvol/lvm.go +++ b/lib/btrfs/btrfsvol/lvm.go @@ -2,6 +2,8 @@ // // SPDX-License-Identifier: GPL-2.0-or-later +// Package btrfsvol contains core logical-volume-management layer of +// btrfs. package btrfsvol import ( diff --git a/lib/btrfs/io1_pv.go b/lib/btrfs/io1_pv.go index 72d33f5..3b13f73 100644 --- a/lib/btrfs/io1_pv.go +++ b/lib/btrfs/io1_pv.go @@ -2,6 +2,8 @@ // // SPDX-License-Identifier: GPL-2.0-or-later +// Package btrfs (and its sub-packages) are the core implementation of +// the btrfs filesystem. package btrfs import ( diff --git a/lib/btrfs/io4_fs.go b/lib/btrfs/io4_fs.go index e146739..b1a1232 100644 --- a/lib/btrfs/io4_fs.go +++ b/lib/btrfs/io4_fs.go @@ -122,7 +122,7 @@ func (sv *Subvolume) LoadBareInode(inode btrfsprim.ObjID) (*BareInode, error) { }) if err != nil { val.Errs = append(val.Errs, err) - return + return val } switch itemBody := item.Body.(type) { @@ -135,7 +135,7 @@ func (sv *Subvolume) LoadBareInode(inode btrfsprim.ObjID) (*BareInode, error) { panic(fmt.Errorf("should not happen: INODE_ITEM has unexpected item type: %T", itemBody)) } - return + return val }) if val.InodeItem == nil { return nil, val.Errs @@ -156,7 +156,7 @@ func (sv *Subvolume) LoadFullInode(inode btrfsprim.ObjID) (*FullInode, error) { if err != nil { val.Errs = append(val.Errs, err) if len(items) == 0 { - return + return val } } for _, item := range items { @@ -190,7 +190,7 @@ func (sv *Subvolume) LoadFullInode(inode btrfsprim.ObjID) (*FullInode, error) { val.OtherItems = append(val.OtherItems, item) } } - return + return val }) if val.InodeItem == nil && val.OtherItems == nil { return nil, val.Errs @@ -205,12 +205,12 @@ func (sv *Subvolume) LoadDir(inode btrfsprim.ObjID) (*Dir, error) { fullInode, err := sv.LoadFullInode(inode) if err != nil { val.Errs = append(val.Errs, err) - return + return val } val.FullInode = *fullInode val.SV = sv val.populate() - return + return val }) if val.Inode == 0 { return nil, val.Errs @@ -342,12 +342,12 @@ func (sv *Subvolume) LoadFile(inode btrfsprim.ObjID) (*File, error) { fullInode, err := sv.LoadFullInode(inode) if err != nil { val.Errs = append(val.Errs, err) - return + return val } val.FullInode = *fullInode val.SV = sv val.populate() - return + return val }) if val.Inode == 0 { return nil, val.Errs |