summaryrefslogtreecommitdiff
path: root/pkg/btrfs
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/btrfs')
-rw-r--r--pkg/btrfs/io1_device.go27
-rw-r--r--pkg/btrfs/io2_fs.go23
-rw-r--r--pkg/btrfs/types_btree.go18
3 files changed, 45 insertions, 23 deletions
diff --git a/pkg/btrfs/io1_device.go b/pkg/btrfs/io1_device.go
index 55b7525..3b84fcc 100644
--- a/pkg/btrfs/io1_device.go
+++ b/pkg/btrfs/io1_device.go
@@ -10,6 +10,9 @@ import (
type Device struct {
*os.File
+
+ cacheSuperblocks []*util.Ref[PhysicalAddr, Superblock]
+ cacheSuperblock *util.Ref[PhysicalAddr, Superblock]
}
func (dev Device) Size() (PhysicalAddr, error) {
@@ -30,7 +33,10 @@ func (dev *Device) ReadAt(dat []byte, paddr PhysicalAddr) (int, error) {
return dev.File.ReadAt(dat, int64(paddr))
}
-func (dev *Device) Superblocks() ([]util.Ref[PhysicalAddr, Superblock], error) {
+func (dev *Device) Superblocks() ([]*util.Ref[PhysicalAddr, Superblock], error) {
+ if dev.cacheSuperblocks != nil {
+ return dev.cacheSuperblocks, nil
+ }
superblockSize := PhysicalAddr(binstruct.StaticSize(Superblock{}))
sz, err := dev.Size()
@@ -38,10 +44,10 @@ func (dev *Device) Superblocks() ([]util.Ref[PhysicalAddr, Superblock], error) {
return nil, err
}
- var ret []util.Ref[PhysicalAddr, Superblock]
+ var ret []*util.Ref[PhysicalAddr, Superblock]
for i, addr := range SuperblockAddrs {
if addr+superblockSize <= sz {
- superblock := util.Ref[PhysicalAddr, Superblock]{
+ superblock := &util.Ref[PhysicalAddr, Superblock]{
File: dev,
Addr: addr,
}
@@ -54,23 +60,30 @@ func (dev *Device) Superblocks() ([]util.Ref[PhysicalAddr, Superblock], error) {
if len(ret) == 0 {
return nil, fmt.Errorf("no superblocks")
}
+ dev.cacheSuperblocks = ret
return ret, nil
}
-func (dev *Device) Superblock() (ret util.Ref[PhysicalAddr, Superblock], err error) {
+func (dev *Device) Superblock() (*util.Ref[PhysicalAddr, Superblock], error) {
+ if dev.cacheSuperblock != nil {
+ return dev.cacheSuperblock, nil
+ }
sbs, err := dev.Superblocks()
if err != nil {
- return ret, err
+ return nil, err
}
+
for i, sb := range sbs {
if err := sb.Data.ValidateChecksum(); err != nil {
- return ret, fmt.Errorf("superblock %d: %w", i, err)
+ return nil, fmt.Errorf("superblock %d: %w", i, err)
}
if i > 0 {
if !sb.Data.Equal(sbs[0].Data) {
- return ret, fmt.Errorf("superblock %d and superblock %d disagree", 0, i)
+ return nil, fmt.Errorf("superblock %d and superblock %d disagree", 0, i)
}
}
}
+
+ dev.cacheSuperblock = sbs[0]
return sbs[0], nil
}
diff --git a/pkg/btrfs/io2_fs.go b/pkg/btrfs/io2_fs.go
index ae0680a..ff5415a 100644
--- a/pkg/btrfs/io2_fs.go
+++ b/pkg/btrfs/io2_fs.go
@@ -16,6 +16,9 @@ type FS struct {
initErr error
uuid2dev map[UUID]*Device
chunks []SysChunk
+
+ cacheSuperblocks []*util.Ref[PhysicalAddr, Superblock]
+ cacheSuperblock *util.Ref[PhysicalAddr, Superblock]
}
func (fs *FS) Name() string {
@@ -38,8 +41,11 @@ func (fs *FS) Size() (LogicalAddr, error) {
return ret, nil
}
-func (fs *FS) Superblocks() ([]util.Ref[PhysicalAddr, Superblock], error) {
- var ret []util.Ref[PhysicalAddr, Superblock]
+func (fs *FS) Superblocks() ([]*util.Ref[PhysicalAddr, Superblock], error) {
+ if fs.cacheSuperblocks != nil {
+ return fs.cacheSuperblocks, nil
+ }
+ var ret []*util.Ref[PhysicalAddr, Superblock]
for _, dev := range fs.Devices {
sbs, err := dev.Superblocks()
if err != nil {
@@ -47,13 +53,17 @@ func (fs *FS) Superblocks() ([]util.Ref[PhysicalAddr, Superblock], error) {
}
ret = append(ret, sbs...)
}
+ fs.cacheSuperblocks = ret
return ret, nil
}
-func (fs *FS) Superblock() (ret util.Ref[PhysicalAddr, Superblock], err error) {
+func (fs *FS) Superblock() (*util.Ref[PhysicalAddr, Superblock], error) {
+ if fs.cacheSuperblock != nil {
+ return fs.cacheSuperblock, nil
+ }
sbs, err := fs.Superblocks()
if err != nil {
- return ret, err
+ return nil, err
}
fname := ""
@@ -67,19 +77,20 @@ func (fs *FS) Superblock() (ret util.Ref[PhysicalAddr, Superblock], err error) {
}
if err := sb.Data.ValidateChecksum(); err != nil {
- return ret, fmt.Errorf("file %q superblock %d: %w", sb.File.Name(), sbi, err)
+ return nil, fmt.Errorf("file %q superblock %d: %w", sb.File.Name(), sbi, err)
}
if i > 0 {
// This is probably wrong, but lots of my
// multi-device code is probably wrong.
if !sb.Data.Equal(sbs[0].Data) {
- return ret, fmt.Errorf("file %q superblock %d and file %q superblock %d disagree",
+ return nil, fmt.Errorf("file %q superblock %d and file %q superblock %d disagree",
sbs[0].File.Name(), 0,
sb.File.Name(), sbi)
}
}
}
+ fs.cacheSuperblock = sbs[0]
return sbs[0], nil
}
diff --git a/pkg/btrfs/types_btree.go b/pkg/btrfs/types_btree.go
index 8db00e2..5adc7ec 100644
--- a/pkg/btrfs/types_btree.go
+++ b/pkg/btrfs/types_btree.go
@@ -249,49 +249,47 @@ func (node *Node) LeafFreeSpace() uint32 {
return freeSpace
}
-func (fs *FS) ReadNode(addr LogicalAddr) (util.Ref[LogicalAddr, Node], error) {
- var ret util.Ref[LogicalAddr, Node]
-
+func (fs *FS) ReadNode(addr LogicalAddr) (*util.Ref[LogicalAddr, Node], error) {
sb, err := fs.Superblock()
if err != nil {
- return ret, fmt.Errorf("btrfs.FS.ReadNode: %w", err)
+ return nil, fmt.Errorf("btrfs.FS.ReadNode: %w", err)
}
// read
nodeBuf := make([]byte, sb.Data.NodeSize)
if _, err := fs.ReadAt(nodeBuf, addr); err != nil {
- return ret, err
+ return nil, err
}
var node Node
node.Size = sb.Data.NodeSize
if _, err := node.UnmarshalBinary(nodeBuf); err != nil {
- return ret, fmt.Errorf("btrfs.FS.ReadNode: node@%d: %w", addr, err)
+ return nil, fmt.Errorf("btrfs.FS.ReadNode: node@%d: %w", addr, err)
}
// sanity checking
if node.Head.MetadataUUID != sb.Data.EffectiveMetadataUUID() {
- return ret, fmt.Errorf("btrfs.FS.ReadNode: node@%d: does not look like a node", addr)
+ return nil, fmt.Errorf("btrfs.FS.ReadNode: node@%d: does not look like a node", addr)
}
if node.Head.Addr != addr {
- return ret, fmt.Errorf("btrfs.FS.ReadNode: node@%d: read from laddr=%d but claims to be at laddr=%d",
+ return nil, fmt.Errorf("btrfs.FS.ReadNode: node@%d: read from laddr=%d but claims to be at laddr=%d",
addr, addr, node.Head.Addr)
}
stored := node.Head.Checksum
calced := CRC32c(nodeBuf[binstruct.StaticSize(CSum{}):])
if calced != stored {
- return ret, fmt.Errorf("btrfs.FS.ReadNode: node@%d: checksum mismatch: stored=%s calculated=%s",
+ return nil, fmt.Errorf("btrfs.FS.ReadNode: node@%d: checksum mismatch: stored=%s calculated=%s",
addr, stored, calced)
}
// return
- return util.Ref[LogicalAddr, Node]{
+ return &util.Ref[LogicalAddr, Node]{
File: fs,
Addr: addr,
Data: node,