diff options
Diffstat (limited to 'pkg/btrfs')
-rw-r--r-- | pkg/btrfs/io1_device.go | 27 | ||||
-rw-r--r-- | pkg/btrfs/io2_fs.go | 23 | ||||
-rw-r--r-- | pkg/btrfs/types_btree.go | 18 |
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, |