diff options
author | Luke Shumaker <lukeshu@lukeshu.com> | 2022-06-30 04:14:55 -0600 |
---|---|---|
committer | Luke Shumaker <lukeshu@lukeshu.com> | 2022-06-30 04:14:55 -0600 |
commit | b78fe1835fed316bd8e9e51c91fcc05422330490 (patch) | |
tree | eb8ed91bf6160aa732229cc4374eaf0c527b50ef | |
parent | 27d2f3a0efe6de94c7720907557e640e8a2f1428 (diff) |
lock sizes, use blockgroups
-rw-r--r-- | cmd/btrfs-fsck/pass1.go | 37 | ||||
-rw-r--r-- | pkg/btrfs/btrfsitem/item_blockgroup.go | 2 | ||||
-rw-r--r-- | pkg/btrfs/btrfsitem/item_chunk.go | 5 | ||||
-rw-r--r-- | pkg/btrfs/btrfsitem/item_devextent.go | 5 | ||||
-rw-r--r-- | pkg/btrfs/btrfsvol/chunk.go | 20 | ||||
-rw-r--r-- | pkg/btrfs/btrfsvol/devext.go | 18 | ||||
-rw-r--r-- | pkg/btrfs/btrfsvol/lvm.go | 44 |
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) |