summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2022-06-30 04:14:55 -0600
committerLuke Shumaker <lukeshu@lukeshu.com>2022-06-30 04:14:55 -0600
commitb78fe1835fed316bd8e9e51c91fcc05422330490 (patch)
treeeb8ed91bf6160aa732229cc4374eaf0c527b50ef
parent27d2f3a0efe6de94c7720907557e640e8a2f1428 (diff)
lock sizes, use blockgroups
-rw-r--r--cmd/btrfs-fsck/pass1.go37
-rw-r--r--pkg/btrfs/btrfsitem/item_blockgroup.go2
-rw-r--r--pkg/btrfs/btrfsitem/item_chunk.go5
-rw-r--r--pkg/btrfs/btrfsitem/item_devextent.go5
-rw-r--r--pkg/btrfs/btrfsvol/chunk.go20
-rw-r--r--pkg/btrfs/btrfsvol/devext.go18
-rw-r--r--pkg/btrfs/btrfsvol/lvm.go44
7 files changed, 101 insertions, 30 deletions
diff --git a/cmd/btrfs-fsck/pass1.go b/cmd/btrfs-fsck/pass1.go
index a83697f..a7c4a61 100644
--- a/cmd/btrfs-fsck/pass1.go
+++ b/cmd/btrfs-fsck/pass1.go
@@ -116,7 +116,9 @@ func (found pass1ScanOneDevResult) AddToLV(fs *btrfs.FS, dev *btrfs.Device) {
}
// Do the nodes last to avoid bloating the mappings table too
- // much.
+ // much. (Because nodes are numerous and small, while the
+ // others are few and large; so it is likely that many of the
+ // nodes will be subsumed by other things.)
//
// Sort them so that progress numbers are predictable.
laddrs := make([]btrfsvol.LogicalAddr, 0, len(found.FoundNodes))
@@ -136,8 +138,9 @@ func (found pass1ScanOneDevResult) AddToLV(fs *btrfs.FS, dev *btrfs.Device) {
Dev: sb.Data.DevItem.DevID,
Addr: paddr,
},
- Size: btrfsvol.AddrDelta(sb.Data.NodeSize),
- Flags: nil,
+ Size: btrfsvol.AddrDelta(sb.Data.NodeSize),
+ SizeLocked: false,
+ Flags: nil,
}); err != nil {
fmt.Printf("Pass 1: ... error: adding node ident: %v\n", err)
}
@@ -145,6 +148,34 @@ func (found pass1ScanOneDevResult) AddToLV(fs *btrfs.FS, dev *btrfs.Device) {
printProgress()
}
}
+
+ // Use block groups to add missing flags (and as a hint to
+ // combine node entries).
+ for _, bg := range found.FoundBlockGroups {
+ laddr := btrfsvol.LogicalAddr(bg.Key.ObjectID)
+ size := btrfsvol.AddrDelta(bg.Key.Offset)
+
+ otherLAddr, otherPAddr := fs.LV.ResolveAny(laddr, size)
+ if otherLAddr < 0 || otherPAddr.Addr < 0 {
+ continue
+ }
+
+ offsetWithinChunk := otherLAddr.Sub(laddr)
+ flags := bg.BG.Flags
+ mapping := btrfsvol.Mapping{
+ LAddr: laddr,
+ PAddr: btrfsvol.QualifiedPhysicalAddr{
+ Dev: otherPAddr.Dev,
+ Addr: otherPAddr.Addr.Add(-offsetWithinChunk),
+ },
+ Size: size,
+ SizeLocked: true,
+ Flags: &flags,
+ }
+ if err := fs.LV.AddMapping(mapping); err != nil {
+ fmt.Printf("Pass 1: ... error: adding flags from blockgroup: %v\n", err)
+ }
+ }
}
func pass1ScanOneDev(dev *btrfs.Device, superblock btrfs.Superblock) (pass1ScanOneDevResult, error) {
diff --git a/pkg/btrfs/btrfsitem/item_blockgroup.go b/pkg/btrfs/btrfsitem/item_blockgroup.go
index 8f7847d..63cbcbb 100644
--- a/pkg/btrfs/btrfsitem/item_blockgroup.go
+++ b/pkg/btrfs/btrfsitem/item_blockgroup.go
@@ -10,7 +10,7 @@ import (
// key.offset = size of chunk
type BlockGroup struct { // BLOCK_GROUP_ITEM=192
Used int64 `bin:"off=0, siz=8"`
- ChunkObjectID internal.ObjID `bin:"off=8, siz=8"`
+ ChunkObjectID internal.ObjID `bin:"off=8, siz=8"` // always BTRFS_FIRST_CHUNK_TREE_OBJECTID
Flags btrfsvol.BlockGroupFlags `bin:"off=16, siz=8"`
binstruct.End `bin:"off=24"`
}
diff --git a/pkg/btrfs/btrfsitem/item_chunk.go b/pkg/btrfs/btrfsitem/item_chunk.go
index efd9d31..f567506 100644
--- a/pkg/btrfs/btrfsitem/item_chunk.go
+++ b/pkg/btrfs/btrfsitem/item_chunk.go
@@ -47,8 +47,9 @@ func (chunk Chunk) Mappings(key internal.Key) []btrfsvol.Mapping {
Dev: stripe.DeviceID,
Addr: stripe.Offset,
},
- Size: chunk.Head.Size,
- Flags: &chunk.Head.Type,
+ Size: chunk.Head.Size,
+ SizeLocked: true,
+ Flags: &chunk.Head.Type,
})
}
return ret
diff --git a/pkg/btrfs/btrfsitem/item_devextent.go b/pkg/btrfs/btrfsitem/item_devextent.go
index c7707bd..56fba27 100644
--- a/pkg/btrfs/btrfsitem/item_devextent.go
+++ b/pkg/btrfs/btrfsitem/item_devextent.go
@@ -25,7 +25,8 @@ func (devext DevExtent) Mapping(key internal.Key) btrfsvol.Mapping {
Dev: btrfsvol.DeviceID(key.ObjectID),
Addr: btrfsvol.PhysicalAddr(key.Offset),
},
- Size: devext.Length,
- Flags: nil,
+ Size: devext.Length,
+ SizeLocked: true,
+ Flags: nil,
}
}
diff --git a/pkg/btrfs/btrfsvol/chunk.go b/pkg/btrfs/btrfsvol/chunk.go
index e53265f..146193d 100644
--- a/pkg/btrfs/btrfsvol/chunk.go
+++ b/pkg/btrfs/btrfsvol/chunk.go
@@ -9,12 +9,15 @@ import (
// logical => []physical
type chunkMapping struct {
- LAddr LogicalAddr
- PAddrs []QualifiedPhysicalAddr
- Size AddrDelta
- Flags *BlockGroupFlags
+ LAddr LogicalAddr
+ PAddrs []QualifiedPhysicalAddr
+ Size AddrDelta
+ SizeLocked bool
+ Flags *BlockGroupFlags
}
+type ChunkMapping = chunkMapping
+
// return -1 if 'a' is wholly to the left of 'b'
// return 0 if there is some overlap between 'a' and 'b'
// return 1 if 'a is wholly to the right of 'b'
@@ -51,6 +54,15 @@ func (a chunkMapping) union(rest ...chunkMapping) (chunkMapping, error) {
LAddr: beg,
Size: end.Sub(beg),
}
+ for _, chunk := range chunks {
+ if chunk.SizeLocked {
+ ret.SizeLocked = true
+ if ret.Size != chunk.Size {
+ return chunkMapping{}, fmt.Errorf("member chunk has locked size=%v, but union would have size=%v",
+ chunk.Size, ret.Size)
+ }
+ }
+ }
// figure out the physical stripes (.PAddrs)
paddrs := make(map[QualifiedPhysicalAddr]struct{})
for _, chunk := range chunks {
diff --git a/pkg/btrfs/btrfsvol/devext.go b/pkg/btrfs/btrfsvol/devext.go
index 736d39b..8a69c7e 100644
--- a/pkg/btrfs/btrfsvol/devext.go
+++ b/pkg/btrfs/btrfsvol/devext.go
@@ -8,10 +8,11 @@ import (
// physical => logical
type devextMapping struct {
- PAddr PhysicalAddr
- LAddr LogicalAddr
- Size AddrDelta
- Flags *BlockGroupFlags
+ PAddr PhysicalAddr
+ LAddr LogicalAddr
+ Size AddrDelta
+ SizeLocked bool
+ Flags *BlockGroupFlags
}
// return -1 if 'a' is wholly to the left of 'b'
@@ -50,6 +51,15 @@ func (a devextMapping) union(rest ...devextMapping) (devextMapping, error) {
PAddr: beg,
Size: end.Sub(beg),
}
+ for _, ext := range exts {
+ if ext.SizeLocked {
+ ret.SizeLocked = true
+ if ret.Size != ext.Size {
+ return devextMapping{}, fmt.Errorf("member devext has locked size=%v, but union would have size=%v",
+ ext.Size, ret.Size)
+ }
+ }
+ }
// figure out the logical range (.LAddr)
first := true
for _, ext := range exts {
diff --git a/pkg/btrfs/btrfsvol/lvm.go b/pkg/btrfs/btrfsvol/lvm.go
index 078b18e..2857762 100644
--- a/pkg/btrfs/btrfsvol/lvm.go
+++ b/pkg/btrfs/btrfsvol/lvm.go
@@ -3,6 +3,7 @@ package btrfsvol
import (
"bytes"
"fmt"
+ "os"
"reflect"
"lukeshu.com/btrfs-tools/pkg/rbtree"
@@ -91,10 +92,11 @@ func (lv *LogicalVolume[PhysicalVolume]) ClearMappings() {
}
type Mapping struct {
- LAddr LogicalAddr
- PAddr QualifiedPhysicalAddr
- Size AddrDelta
- Flags *BlockGroupFlags
+ LAddr LogicalAddr
+ PAddr QualifiedPhysicalAddr
+ Size AddrDelta
+ SizeLocked bool
+ Flags *BlockGroupFlags
}
func (lv *LogicalVolume[PhysicalVolume]) AddMapping(m Mapping) error {
@@ -107,10 +109,11 @@ func (lv *LogicalVolume[PhysicalVolume]) AddMapping(m Mapping) error {
// logical2physical
newChunk := chunkMapping{
- LAddr: m.LAddr,
- PAddrs: []QualifiedPhysicalAddr{m.PAddr},
- Size: m.Size,
- Flags: m.Flags,
+ LAddr: m.LAddr,
+ PAddrs: []QualifiedPhysicalAddr{m.PAddr},
+ Size: m.Size,
+ SizeLocked: m.SizeLocked,
+ Flags: m.Flags,
}
logicalOverlaps := lv.logical2physical.SearchRange(newChunk.cmpRange)
var err error
@@ -121,10 +124,11 @@ func (lv *LogicalVolume[PhysicalVolume]) AddMapping(m Mapping) error {
// physical2logical
newExt := devextMapping{
- PAddr: m.PAddr.Addr,
- LAddr: m.LAddr,
- Size: m.Size,
- Flags: m.Flags,
+ PAddr: m.PAddr.Addr,
+ LAddr: m.LAddr,
+ Size: m.Size,
+ SizeLocked: m.SizeLocked,
+ Flags: m.Flags,
}
physicalOverlaps := lv.physical2logical[m.PAddr.Dev].SearchRange(newExt.cmpRange)
newExt, err = newExt.union(physicalOverlaps...)
@@ -154,8 +158,10 @@ func (lv *LogicalVolume[PhysicalVolume]) AddMapping(m Mapping) error {
//
// This is in-theory unnescessary, but that assumes that I
// made no mistakes in my algorithm above.
- if err := lv.fsck(); err != nil {
- return err
+ if os.Getenv("PARANOID") != "" {
+ if err := lv.fsck(); err != nil {
+ return err
+ }
}
// done
@@ -249,6 +255,16 @@ func (lv *LogicalVolume[PhysicalVolume]) Resolve(laddr LogicalAddr) (paddrs map[
return paddrs, maxlen
}
+func (lv *LogicalVolume[PhysicalVolume]) ResolveAny(laddr LogicalAddr, size AddrDelta) (LogicalAddr, QualifiedPhysicalAddr) {
+ node := lv.logical2physical.Search(func(chunk chunkMapping) int {
+ return chunkMapping{LAddr: laddr, Size: size}.cmpRange(chunk)
+ })
+ if node == nil {
+ return -1, QualifiedPhysicalAddr{0, -1}
+ }
+ return node.Value.LAddr, node.Value.PAddrs[0]
+}
+
func (lv *LogicalVolume[PhysicalVolume]) UnResolve(paddr QualifiedPhysicalAddr) LogicalAddr {
node := lv.physical2logical[paddr.Dev].Search(func(ext devextMapping) int {
return devextMapping{PAddr: paddr.Addr, Size: 1}.cmpRange(ext)